packages feed

graphql-w-persistent 0.3.2.1 → 0.4.0.0

raw patch · 15 files changed

+1017/−811 lines, 15 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- GraphQL: EmptyRowException :: QueryException
- GraphQL: Foundlinebreakexception :: QueryException
- GraphQL: InvalidAttributeTransformation :: QueryException
- GraphQL: InvalidDirectiveException :: QueryException
- GraphQL: InvalidObjectNestedObjectFieldException :: QueryException
- GraphQL: NestedObject :: Alias -> Name -> ServerObject -> SubSelection -> SubFields -> NestedObject
- GraphQL: ScalarType :: Alias -> Name -> Transformation -> Argument -> ScalarType
- GraphQL: TooManyTablesException :: QueryException
- GraphQL: ValueInterpretationException :: QueryException
- GraphQL: VariableException :: QueryException
- GraphQL: data NestedObject
- GraphQL: data ScalarType
- GraphQL: processPersistentData :: [(String, [(String, String)])] -> [[[[Text]]]] -> [RootObject] -> String
- GraphQL: processPersistentDataWithJson :: MonadIO m => FilePath -> [[[[Text]]]] -> [RootObject] -> m String
- GraphQL: processQueryStringWithJson :: MonadIO m => String -> FilePath -> m ([RootObject], [[String]])
- GraphQL: processQueryStringWithJsonAndVariables :: MonadIO m => String -> String -> FilePath -> m ([RootObject], [[String]])
- GraphQL: processQueryStringWithVariables :: String -> String -> [(String, [String])] -> [(String, [(String, String)])] -> [(String, [String])] -> [(String, [String])] -> [(String, String, [String])] -> ([RootObject], [[String]])
- GraphQL: type Alias = Maybe String
- GraphQL: type Argument = Maybe String
- GraphQL: type Field = Either ScalarType NestedObject
- GraphQL: type Name = String
- GraphQL: type RootObject = NestedObject
- GraphQL: type RootObjects = [RootObject]
- GraphQL: type ServerObject = String
- GraphQL: type SubFields = [Field]
- GraphQL: type SubSelection = Maybe ScalarType
- GraphQL: type Transformation = Maybe String
+ GraphQL: ImportSchemaChildrenException :: QueryException
+ GraphQL: processQueryData :: MonadIO m => FilePath -> [(RootObject, [[String]])] -> [[[[Text]]]] -> m String
- GraphQL: processQueryString :: String -> [(String, [String])] -> [(String, [(String, String)])] -> [(String, [String])] -> [(String, [String])] -> [(String, String, [String])] -> ([RootObject], [[String]])
+ GraphQL: processQueryString :: MonadIO m => FilePath -> String -> String -> m ([(RootObject, [[String]])], [[String]])

Files

ChangeLog.md view
@@ -1,5 +1,9 @@ # Revision history for graphql-w-persistent
 
+## 0.4.0.0 -- 2019-06-17
+
+* add inline fragments and comment lines
+
 ## 0.3.2.1 -- 2019-05-18
 
 * fix variables bug (now supporting multiple variables), database query bug (translating correctly nested objects), fragments bug (within variables are now supported), and added include and skip directives support
graphql-w-persistent.cabal view
@@ -10,13 +10,13 @@ -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             0.3.2.1
+version:             0.4.0.0
 
 -- A short (one-line) description of the package.
 synopsis:            Haskell GraphQL query parser-interpreter-data processor.
 
 -- A longer description of the package.
-description:      This is a Haskell GraphQL query parser and interpreter. It is including data processing to return GraphQL object formats. The query parser and interpreter are universal (on available database query types which is only SQL for now). It is accepting any string query, and it is returning a list of string database-queries. The data processing unit is designed about the return values from the Yesod and Persistent interface (casted as Text data values from PersistValue). With another database package that is same data structure on the returned values from the database, this entire package is applicable. Examples are odbc package query function and HDBC package quickQuery. To read more detailed information, you should go to the below module page.
+description:      This is a Haskell GraphQL query parser and interpreter. There is data processing to return GraphQL object formats. The query parser and interpreter are always applicable (on available database query types which is only SQL for now). It is accepting any string query, and it is returning a list of string database-queries. The data processing function is designed about the return values from the Persistent library (casted as Text data values from PersistValue). With another database package with same data structure on the returned values from the database, this whole package is applicable. Examples are odbc package query function and HDBC package quickQuery. To read more detailed information, you should go to the below module page.
 
 -- URL for the project homepage or repository.
 homepage:            https://github.com/jasonsychau/graphql-w-persistent
@@ -61,7 +61,7 @@   exposed-modules:     GraphQL
 
   -- Modules included in this library but not exported.
-  other-modules:       Components.DataProcessors.PersistentDataProcessor,
+  other-modules:       Components.DataProcessors.ListDataProcessor,
                        Components.ObjectHandlers.ObjectsHandler,
                        Components.ObjectHandlers.ServerObjectValidator,
                        Components.ObjectHandlers.ServerObjectTrimmer,
@@ -70,8 +70,7 @@                        Components.Parsers.QueryParser,
                        Components.QueryComposers.SQLQueryComposer,
                        Model.ServerObjectTypes,
-                       Model.ServerExceptions,
-                       GraphQLHelper
+                       Model.ServerExceptions
 
   -- LANGUAGE extensions used by modules in this package.
   --other-extensions:
+ src/Components/DataProcessors/ListDataProcessor.hs view
@@ -0,0 +1,126 @@+module Components.DataProcessors.ListDataProcessor (processReturnedValues) where
+
+
+import Model.ServerExceptions (
+        QueryException(
+            InvalidObjectException,
+            InvalidScalarException,
+            InvalidArgumentException,
+            EOFDataProcessingException,
+            InvalidVariableTypeException,
+            InvalidObjectScalarFieldException
+        )
+    )
+import Model.ServerObjectTypes (NestedObject(..),Field,RootObject)
+import Components.ObjectHandlers.ObjectsHandler (
+        getSubFields,
+        getServerObject,
+        getInlinefragmentFields,
+        getInlinefragmentObject,
+        translateServerObjectToDBName,
+        isServerObjectTable,
+        getNestedObjectFieldLabel,
+        getScalarName,
+        getScalarFieldLabel,
+        getServerObjectScalars
+    )
+import Data.Maybe (Maybe(Nothing),fromJust)
+import Data.Either (fromRight,fromLeft,isLeft)
+import Data.Text (Text,unpack)
+import Text.JSON (showJSON,showJSONs,JSValue,JSObject,toJSObject,encodeStrict)
+import Control.Exception (throw)
+
+
+-- with root objects we want one json representation of separate graphql results...
+processReturnedValues :: [(String,[(String,String)])] -> [(String,String)] -> [(String,[String],[String])] -> [RootObject] -> [[[String]]] -> [[[[Text]]]] -> String
+processReturnedValues sss sodn soa robjs tbls rlts = encodeStrict $ processReturnedValuesToJsonObject sss sodn soa robjs tbls rlts
+processReturnedValuesToJsonObject :: [(String,[(String,String)])] -> [(String,String)] -> [(String,[String],[String])] -> [RootObject] -> [[[String]]] -> [[[[Text]]]] -> JSObject (JSObject JSValue)
+processReturnedValuesToJsonObject sss sodn soa robjs tbls rlts = toJSObject [("data", toJSObject [processReturnedValue sss sodn soa x y z | (x,y,z) <- zip3 robjs tbls rlts])]
+-- with qraphql query object and sql return data, we want json representation on graphql query results...
+processReturnedValue :: [(String,[(String,String)])] -> [(String,String)] -> [(String,[String],[String])] -> RootObject -> [[String]] -> [[[Text]]] -> (String, JSValue)
+processReturnedValue sss sodn soa (NestedObject alias name sobj _ sfs) tbls rlts = (if (alias==Nothing) then name else (fromJust alias), showJSONs $ processSubFields sss sodn soa sobj tbls sfs rlts)
+-- with SubFields and data rows, we want json representation on qraphql query data
+processSubFields :: [(String,[(String,String)])] -> [(String,String)] -> [(String,[String],[String])] -> String -> [[String]] -> [Field] -> [[[Text]]] -> [JSValue]
+processSubFields _ _ _ _ _ _ [] = []
+processSubFields _ _ _ _ _ [] _ = []
+-- are the query results from unique objects to make separate objects
+-- assume that if last table is same, fetchNextRow is same object instance
+processSubFields sss sodn soa sobj tbls sfs rlts
+    | (null $ foldr (++) [] rlts)==True = []
+    | (foldr (\x y->(last x)==(last $ head tbls)&&y) True tbls) = ((showJSON $ toJSObject object):(processSubFields sss sodn soa sobj tbls sfs [removeDataRow x | x<-rlts]))
+    | otherwise = ([showJSON $ toJSObject x | x<-objects]++(processSubFields sss sodn soa sobj tbls sfs [removeDataRow x | x<-rlts]))
+  where
+    object = makeOneGQLObject sss sodn soa sobj tbls sfs [fetchGraphQlRow x | x<-rlts]
+    -- assume tbls are segmented from last table
+    groupedData :: [[([String],[[Text]])]]
+    groupedData = foldr (\(x,y) z -> if (null z)==True then [[(x,y)]] else if (last x)==(last $ fst $ head $ head z) then (((x,y):(head z)):(tail z)) else ([(x,y)]:z)) [] $ zip tbls [fetchGraphQlRow x | x<-rlts]
+    objects = foldr (\x y -> (makeOneGQLObject sss sodn soa sobj [i | (i,_)<-x] sfs [j | (_,j)<-x]):y) [] groupedData
+-- assume all last elements are same in tbls
+-- assume all instances (ist) are same
+makeOneGQLObject :: [(String,[(String,String)])] -> [(String,String)] -> [(String,[String],[String])] -> String -> [[String]] -> [Field] -> [[[Text]]] -> [(String,JSValue)]
+makeOneGQLObject _ _ _ _ _ [] (([]:_):_) = []  -- done
+makeOneGQLObject _ _ _ _ _ _ ([]:_) = []  -- no data
+makeOneGQLObject _ _ _ _ _ _ [] = []  -- no queries (unusual)
+makeOneGQLObject _ _ _ _ _ [] _ = throw EOFDataProcessingException  -- columns and no fields
+makeOneGQLObject _ _ _ _ [] _ _ = throw EOFDataProcessingException  -- no reference tables (unusual)
+makeOneGQLObject _ sodn soa sobj tbls (f:[]) (([]:_):_) = if (isLeft f)==True||(isLeft fo)==True||(isServerObjectTable (last $ head tbls) (getInlinefragmentObject ifo) sodn soa)==False then [] else throw EOFDataProcessingException -- fields and no result columns
+                                                      where
+                                                        fo = fromRight (throw InvalidObjectException) f
+                                                        ifo = fromRight (throw InvalidObjectException) fo
+makeOneGQLObject _ _ _ _ _ _ (([]:_):_) = throw EOFDataProcessingException  -- fields and no result columns
+makeOneGQLObject sss sodn soa sobj tbls (a:b) (((i:j):k):l)  -- (((:fld):ist):qry)
+    | (isLeft a)==True = ((getScalarFieldLabel scalarField, castJSType (getServerObjectScalars sobj sss soa) (getScalarName scalarField) i):(makeOneGQLObject sss sodn soa sobj tbls b [removeNDataColumns 1 x | x<-(((i:j):k):l)]))
+    | (isLeft fo)==True = (((getNestedObjectFieldLabel no), showJSONs (processSubFields sss sodn soa (getServerObject no) nxtTbls (getSubFields no) [pullNDataColumns x y | (x,y)<-zip nestedObjectFieldCounts (((i:j):k):l)])):(makeOneGQLObject sss sodn soa sobj tbls b [removeNDataColumns x y | (x,y)<-zip nestedObjectFieldCounts (((i:j):k):l)]))
+    | (isServerObjectTable (last $ head tbls) (getInlinefragmentObject ifo) sodn soa)==True = makeOneGQLObject sss sodn soa sobj tbls ((getInlinefragmentFields ifo)++b) (((i:j):k):l)
+    | otherwise = makeOneGQLObject sss sodn soa sobj tbls b (((i:j):k):l)
+  where
+    nxtTbls = [init x | x<-tbls]
+    nestedObjectFieldCounts = [countNOQueriedFields sodn soa no x | x<-nxtTbls]
+    scalarField = (fromLeft (throw InvalidScalarException) a)
+    fo = fromRight (throw InvalidObjectException) a
+    no = fromLeft (throw InvalidObjectException) fo
+    ifo = fromRight (throw InvalidObjectException) fo 
+fetchGraphQlRow :: [[Text]] -> [[Text]]
+fetchGraphQlRow rlts = [t | (h:t)<-rlts, ((h)==(head $ head rlts))&&((head t)==(head $ tail $ head rlts))]
+removeDataRow :: [[Text]] -> [[Text]]
+removeDataRow rlts = [x | x<-rlts, (head x)/=(head $ head rlts)||((head $ tail x)/=(head $ tail $ head rlts))]
+pullNDataColumns :: Int -> [[Text]] -> [[Text]]
+pullNDataColumns _ [] = []
+pullNDataColumns cnt rslt
+    | (cnt<0) = throw InvalidArgumentException
+    | otherwise = [if (length x)<cnt then (throw EOFDataProcessingException) else (take cnt x) | x<-rslt]
+-- count how many columns are added to sql data result for this nested object including the nested object id
+countNOQueriedFields :: [(String,String)] -> [(String,[String],[String])] -> NestedObject -> [String] -> Int
+countNOQueriedFields sodn soa (NestedObject alias name sobj ss sfs) tbls = 1+(countNOQueriedSubFields sodn soa sfs tbls)
+countNOQueriedSubFields :: [(String,String)] -> [(String,[String],[String])] -> [Field] -> [String] -> Int
+countNOQueriedSubFields _ _ [] _ = 0
+countNOQueriedSubFields sodn soa (h:t) tbls
+    | (isLeft h)==True = 1+(countNOQueriedSubFields sodn soa t tbls)
+    | (isLeft fo)==True = (countNOQueriedFields sodn soa no $ init tbls)+(countNOQueriedSubFields sodn soa t tbls)
+    | (isServerObjectTable (last tbls) (getInlinefragmentObject ifo) sodn soa)==True = countNOQueriedSubFields sodn soa ((getInlinefragmentFields ifo)++t) tbls
+    | otherwise = countNOQueriedSubFields sodn soa t tbls
+  where
+    fo = fromRight (throw InvalidObjectException) h
+    no = fromLeft (throw InvalidObjectException) fo
+    ifo = fromRight (throw InvalidObjectException) fo
+-- remove nested object columns from data row that is including nested object id
+removeNDataColumns :: Int -> [[Text]] -> [[Text]]
+removeNDataColumns 0 rslt = rslt
+removeNDataColumns (-1) _ = throw EOFDataProcessingException
+removeNDataColumns _ [[]] = [[]]
+removeNDataColumns _ ([]:t) = throw EOFDataProcessingException
+removeNDataColumns cnt rslt = removeNDataColumns (cnt-1) [t | (h:t)<-rslt]
+castJSType :: [(String,String)] -> String -> Text -> JSValue
+castJSType [] fld val = throw InvalidObjectScalarFieldException
+castJSType ((nam,typ):t) fld val
+    | (nam==fld)&&(typ=="Text") = showJSON val
+    | (nam==fld)&&(typ=="ByteString") = showJSON val
+    | (nam==fld)&&(typ=="Int") = showJSON (Prelude.read $ unpack val :: Int)
+    | (nam==fld)&&(typ=="Double") = showJSON (Prelude.read $ unpack val :: Double)
+    | (nam==fld)&&(typ=="Rational") = showJSON (Prelude.read $ unpack val :: Double)
+    | (nam==fld)&&(typ=="Bool") = showJSON (Prelude.read $ unpack val :: Int)
+    | (nam==fld)&&(typ=="Day") = showJSON val
+    | (nam==fld)&&(typ=="TimeOfDay") = showJSON val
+    | (nam==fld)&&(typ=="UTCTime") = showJSON val
+    | (nam==fld) = throw InvalidVariableTypeException
+    | otherwise = castJSType t fld val
− src/Components/DataProcessors/PersistentDataProcessor.hs
@@ -1,85 +0,0 @@-module Components.DataProcessors.PersistentDataProcessor (processReturnedValues) where
-
-import Data.Maybe
-import Data.Either
-import Data.Text (Text,unpack)
-import Text.JSON
-import qualified Control.Exception as E
-import Model.ServerExceptions
-import Model.ServerObjectTypes
-import Components.ObjectHandlers.ObjectsHandler (getSubFields)
-
-
--- with root objects we want one json representation of separate graphql results...
-processReturnedValues :: [(String,[(String,String)])] -> [RootObject] -> [[[[Text]]]] -> String
-processReturnedValues sss robjs rlts = encodeStrict $ processReturnedValuesToJsonObject sss robjs rlts
-processReturnedValuesToJsonObject :: [(String,[(String,String)])] -> [RootObject] -> [[[[Text]]]] -> JSObject (JSObject JSValue)
-processReturnedValuesToJsonObject sss robjs rlts = toJSObject [("data", toJSObject [processReturnedValue sss x y | (x,y) <- zip robjs rlts])]
--- with qraphql query object and sql return data, we want json representation on graphql query results...
-processReturnedValue :: [(String,[(String,String)])] -> RootObject -> [[[Text]]] -> (String, JSValue)
-processReturnedValue sss (NestedObject alias name sobj _ sfs) rlts = (if (alias==Nothing) then name else (fromJust alias), showJSONs $ processSubFields sss sobj sfs rlts)
--- with SubFields and data rows, we want json representation on qraphql query data
-processSubFields :: [(String,[(String,String)])] -> String -> [Field] -> [[[Text]]] -> [JSValue]
-processSubFields _ _ _ [] = []
-processSubFields _ _ [] _ = []
-processSubFields sss sobj sfs rlts = if length(dta)>0 then ((showJSON $ toJSObject $ composeGraphQlRow sss sobj sfs $ fetchGraphQlRow dta):(processSubFields sss sobj sfs [removeDataRow dta])) else []
-                                        where
-                                            dta = foldr (\x y -> x++y) [] rlts
-composeGraphQlRow :: [(String,[(String,String)])] -> String -> [Field] -> [[Text]] -> [(String,JSValue)]
-composeGraphQlRow _ _ [] ([]:t) = [] -- done
--- composeGraphQlRow _ _ _ [] = [] -- no data
-composeGraphQlRow _ _ _ ([]:t) = E.throw EOFDataProcessingException
-composeGraphQlRow _ _ [] _ = E.throw EOFDataProcessingException
-composeGraphQlRow sss sobj (a:b) ((h:t):j)
-    | (isLeft a)==True = ((getScalarFieldLabel scalarField, castJSType (getScalarFields sobj sss) (getScalarFieldName scalarField) h):(composeGraphQlRow sss sobj b (removeNDataColumns 1 ((h:t):j))))
-    | otherwise = (((getNestedObjectFieldLabel $ fromRight (E.throw InvalidObjectException) a), showJSONs (processSubFields sss sobj (getSubFields $ fromRight (E.throw InvalidObjectException) a) [pullNDataColumns nestedObjectFieldCount ((h:t):j)])):(composeGraphQlRow sss sobj b (removeNDataColumns nestedObjectFieldCount ((h:t):j))))
-  where
-    nestedObjectFieldCount = (countNestedObjectQueriedFields $ fromRight (E.throw InvalidObjectException) a)
-    scalarField = (fromLeft (E.throw InvalidScalarException) a)
-fetchGraphQlRow :: [[Text]] -> [[Text]]
-fetchGraphQlRow rlts = [t | (h:t)<-rlts, ((h)==(head $ head rlts))&&((head t)==(head $ tail $ head rlts))]
-removeDataRow :: [[Text]] -> [[Text]]
-removeDataRow rlts = [x | x<-rlts, (head x)/=(head $ head rlts)||((head $ tail x)/=(head $ tail $ head rlts))]
-getScalarFieldLabel :: ScalarType -> String
-getScalarFieldLabel (ScalarType alias name trans arg) = if (alias/=Nothing) then (fromJust alias) else name
-getScalarFieldName :: ScalarType -> String
-getScalarFieldName (ScalarType alias name trans arg) = name
-getNestedObjectFieldLabel :: NestedObject -> String
-getNestedObjectFieldLabel (NestedObject alias name sobj ss sfs) = if (alias/=Nothing) then (fromJust alias) else name
-pullNDataColumns :: Int -> [[Text]] -> [[Text]]
-pullNDataColumns _ [] = []
-pullNDataColumns cnt rslt
-    | (cnt<0) = E.throw InvalidArgumentException
-    | otherwise = [if (length x)<cnt then (E.throw EOFDataProcessingException) else (take cnt x) | x<-rslt]
--- count how many columns are added to sql data result for this nested object including the nested object id
-countNestedObjectQueriedFields :: NestedObject -> Int
-countNestedObjectQueriedFields (NestedObject alias name sobj ss sfs) = 1+(countNestedObjectQueriedSubFields sfs)
-countNestedObjectQueriedSubFields :: [Field] -> Int
-countNestedObjectQueriedSubFields [] = 0
-countNestedObjectQueriedSubFields (h:t)
- | (isLeft h)==True = 1+(countNestedObjectQueriedSubFields t)
- | otherwise = (countNestedObjectQueriedFields (fromRight (E.throw InvalidObjectException) h))+(countNestedObjectQueriedSubFields t) 
--- remove nested object columns from data row that is including nested object id
-removeNDataColumns :: Int -> [[Text]] -> [[Text]]
-removeNDataColumns 0 rslt = rslt
-removeNDataColumns (-1) _ = E.throw EOFDataProcessingException
-removeNDataColumns _ [[]] = [[]]
-removeNDataColumns _ ([]:t) = E.throw EOFDataProcessingException
-removeNDataColumns cnt rslt = removeNDataColumns (cnt-1) [t | (h:t)<-rslt]
-getScalarFields :: String -> [(String,[(String,String)])] -> [(String,String)]
-getScalarFields sobj [] = E.throw InvalidObjectException
-getScalarFields sobj ((nam,oflds):t) = if (sobj==nam) then oflds else (getScalarFields sobj t)
-castJSType :: [(String,String)] -> String -> Text -> JSValue
-castJSType [] fld val = E.throw InvalidObjectScalarFieldException
-castJSType ((nam,typ):t) fld val
-    | (nam==fld)&&(typ=="Text") = showJSON val
-    | (nam==fld)&&(typ=="ByteString") = showJSON val
-    | (nam==fld)&&(typ=="Int") = showJSON (Prelude.read $ unpack val :: Int)
-    | (nam==fld)&&(typ=="Double") = showJSON (Prelude.read $ unpack val :: Double)
-    | (nam==fld)&&(typ=="Rational") = showJSON (Prelude.read $ unpack val :: Double)
-    | (nam==fld)&&(typ=="Bool") = showJSON (Prelude.read $ unpack val :: Int)
-    | (nam==fld)&&(typ=="Day") = showJSON val
-    | (nam==fld)&&(typ=="TimeOfDay") = showJSON val
-    | (nam==fld)&&(typ=="UTCTime") = showJSON val
-    | (nam==fld) = E.throw InvalidVariableTypeException
-    | otherwise = castJSType t fld val
src/Components/ObjectHandlers/ObjectsHandler.hs view
@@ -1,61 +1,89 @@ module Components.ObjectHandlers.ObjectsHandler where
 
-import Data.Maybe
-import qualified Control.Exception as E
-import Model.ServerExceptions
-import Model.ServerObjectTypes
 
+import Model.ServerExceptions (
+        QueryException(
+            InvalidObjectException,
+            RelationshipConfigurationException,
+            NullArgumentException
+        )
+    )
+import Model.ServerObjectTypes (
+        NestedObject(..),
+        ServerObject,
+        ScalarType(..),
+        Alias,
+        SubSelection,
+        SubFields,
+        Field,
+        InlinefragmentObject(..),
+        Argument,
+        Transformation
+    )
+import Data.Maybe (fromJust,Maybe(Nothing))
+import Control.Exception (throw)
 
 {-
 parsing frontend query to server query
 - A valid argument is any string that is provided to reference database objects
 -}
-readServerObject :: String -> [(String,[String])] -> ServerObject
-readServerObject str [] = E.throw InvalidObjectException
-readServerObject str ((a,b):t) = if (elem str b)==True then (a :: ServerObject) else readServerObject str t
+readServerObject :: String -> [(String,[String])] -> [(String,[String],[String])] -> ServerObject
+readServerObject str [] [] = throw InvalidObjectException
+readServerObject str ((a,b):t) c = if (elem str b)==True then (a :: ServerObject) else readServerObject str t c
+readServerObject str [] ((a,b,_):t) = if (elem str b)==True then (a :: ServerObject) else readServerObject str [] t
+
 {-
 checking server type attributes
 -}
 -- EFFECT: returns exclusive list of valid fields that are found in the database table for each Server object 
 -- this is used to check queries against valid subfields
-isValidServerObjectScalarField :: ServerObject -> String -> [(String,[(String,String)])] -> Bool
-isValidServerObjectScalarField _ _ [] = E.throw InvalidObjectException
-isValidServerObjectScalarField sobj name ((a,b):t)
-    | sobj==a&&(elem name $ getScalarNames b)==True = True
-    | sobj==a = False
-    | otherwise = isValidServerObjectScalarField sobj name t
+isValidServerObjectScalarField :: ServerObject -> String -> [(String,[(String,String)])] -> [(String,[String],[String])] -> Bool
+isValidServerObjectScalarField _ _ [] _ = throw InvalidObjectException
+isValidServerObjectScalarField sobj name pvs ((pnt,_,cdn):t) = if sobj==pnt then (foldr (\x y->(isValidServerObjectScalarField x name pvs [])&&y) True cdn)||(isValidServerObjectScalarField sobj name pvs t) else isValidServerObjectScalarField sobj name pvs t
+isValidServerObjectScalarField sobj name ((ptv,fds):t) _
+    | sobj==ptv&&(elem name $ getScalarNames fds)==True = True
+    -- | sobj==a = False
+    | otherwise = isValidServerObjectScalarField sobj name t []
 getScalarNames :: [(String,String)] -> [String]
 getScalarNames lst = [a | (a,b) <- lst]
+
 -- you can create as many relationships as you want with your server...
-isValidServerObjectNestedObjectField :: ServerObject -> String -> [(String,[String])] -> Bool
-isValidServerObjectNestedObjectField _ _ [] = E.throw InvalidObjectException
-isValidServerObjectNestedObjectField sobj name ((a,b):t)
+isValidServerObjectNestedObjectField :: ServerObject -> String -> [(String,[String])] -> [(String,[String],[String])] -> Bool
+isValidServerObjectNestedObjectField sobj name pvo ((so,_,cdn):t) = if sobj==so then (elem name $ getParentObjects cdn pvo)||(isValidServerObjectNestedObjectField sobj name pvo t) else isValidServerObjectNestedObjectField sobj name pvo t
+isValidServerObjectNestedObjectField _ _ [] _ = throw InvalidObjectException
+isValidServerObjectNestedObjectField sobj name ((a,b):t) _ 
     | sobj==a&&(elem name b)==True = True
-    | sobj==a = False
-    | otherwise = isValidServerObjectNestedObjectField sobj name t
+    -- | sobj==a = False
+    | otherwise = isValidServerObjectNestedObjectField sobj name t []
+
 -- split server object to sql query
 -- EFFECTS: returns the database table references for the server object.
-translateServerObjectToDBName :: ServerObject -> [(String,[String])] -> [String]
-translateServerObjectToDBName _ [] = E.throw InvalidObjectException
-translateServerObjectToDBName sobj ((a,b):t)
-    | sobj==a = b
-    | otherwise = translateServerObjectToDBName sobj t
+translateServerObjectToDBName :: ServerObject -> [(String,String)] -> [(String,[String],[String])] -> [String]
+translateServerObjectToDBName sobj pdn ((so,_,cdn):t) = if sobj==so then (foldr (\x y -> (translateServerObjectToDBName x pdn [])++y) [] cdn)++(translateServerObjectToDBName sobj pdn t) else translateServerObjectToDBName sobj pdn t
+translateServerObjectToDBName _ [] _ = []  -- throw InvalidObjectException
+translateServerObjectToDBName sobj ((a,b):t) _
+    | sobj==a = [b]
+    | otherwise = translateServerObjectToDBName sobj t []
 -- TODO: list all server objects and their associated entities
 -- EFFECT: with serverobject and serverobject attribute, we want the identity table, identity field, reference table, reference field, and triple elements if present of identity-to-reference-tables-order intermediate table, to-intermediate field, and from-itermediate field
 -- You can define direct relationships (around only one link) or indirect (but you'll code the database query by yourself...)
 getDBObjectRelationships :: String -> String -> [(String,String,[String])] -> [String]
-getDBObjectRelationships _ _ [] = E.throw RelationshipConfigurationException
+getDBObjectRelationships _ _ [] = throw RelationshipConfigurationException
 getDBObjectRelationships from to ((a,b,c):t)
     | from==a&&to==b = c
     | otherwise = getDBObjectRelationships from to t
 
-
+-- SCALAR FIELDS
 getScalarName :: ScalarType -> String
 getScalarName (ScalarType alias name trans arg) = name
 getScalarArgument :: ScalarType -> String
-getScalarArgument (ScalarType alias name trans arg) = if arg==Nothing then (E.throw NullArgumentException) else (fromJust arg)
+getScalarArgument (ScalarType alias name trans arg) = if arg==Nothing then (throw NullArgumentException) else (fromJust arg)
 getTransformation :: ScalarType -> (Transformation,Argument)
 getTransformation (ScalarType alias name trans arg) = (trans,arg)
+getScalarFieldLabel :: ScalarType -> String
+getScalarFieldLabel (ScalarType alias name trans arg) = if (alias/=Nothing) then (fromJust alias) else name
+
+-- NESTED OBJECTS
 getObjectName :: NestedObject -> String
 getObjectName (NestedObject alias name sobj ss sf) = name
 getObjectAlias :: NestedObject -> Alias
@@ -72,7 +100,43 @@ getSubSelectionArgument (NestedObject alias name sobj ss sf) = getScalarArgument $ fromJust ss
 getSubFields :: NestedObject -> SubFields
 getSubFields (NestedObject alias name sobj ss sf) = sf
-isSameObjectReference :: NestedObject -> NestedObject -> Bool
-isSameObjectReference (NestedObject alias1 name1 sobj1 ss1 sfs1) (NestedObject alias2 name2 sobj2 ss2 sfs2) = alias1==alias2&&name1==name2&&sobj1==sobj2
+isSameNObjectReference :: NestedObject -> NestedObject -> Bool
+isSameNObjectReference (NestedObject alias1 name1 sobj1 ss1 sfs1) (NestedObject alias2 name2 sobj2 ss2 sfs2) = alias1==alias2&&name1==name2&&sobj1==sobj2
 isSameObjectSubSelection :: NestedObject -> NestedObject -> Bool
-isSameObjectSubSelection (NestedObject alias1 name1 sobj1 ss1 sfs1) (NestedObject alias2 name2 sobj2 ss2 sfs2) = ss1==ss2+isSameObjectSubSelection (NestedObject alias1 name1 sobj1 ss1 sfs1) (NestedObject alias2 name2 sobj2 ss2 sfs2) = ss1==ss2
+getNestedObjectFieldLabel :: NestedObject -> String
+getNestedObjectFieldLabel (NestedObject alias name sobj ss sfs) = if (alias/=Nothing) then (fromJust alias) else name
+
+-- INLINE-FRAGMENTS
+isSameIFObjectReference :: InlinefragmentObject -> InlinefragmentObject -> Bool
+isSameIFObjectReference (InlinefragmentObject obj1 sf1) (InlinefragmentObject obj2 sf2) = obj1==obj2
+getInlinefragmentObject :: InlinefragmentObject -> ServerObject
+getInlinefragmentObject (InlinefragmentObject obj sf) = obj
+getInlinefragmentFields :: InlinefragmentObject -> [Field]
+getInlinefragmentFields (InlinefragmentObject obj sf) = sf
+
+-- SERVER OBJECTS
+isValidServerObjectChild :: ServerObject -> ServerObject -> [(String,[String],[String])] -> Bool
+isValidServerObjectChild _ _ [] = False
+isValidServerObjectChild pnt cld ((so,_,cdn):t) = if pnt==so then (elem cld cdn)||(isValidServerObjectChild pnt cld t) else isValidServerObjectChild pnt cld t
+getServerObjectScalars :: ServerObject -> [(String,[(String,String)])] -> [(String,[String],[String])] -> [(String,String)]
+getServerObjectScalars _ [] _ = throw InvalidObjectException
+getServerObjectScalars sobj sss ((pnt,_,cdn):t) = if (sobj==pnt) then getIntersection [getServerObjectScalars x sss [] | x<-cdn] else getServerObjectScalars sobj sss t
+getServerObjectScalars sobj ((cld,fds):t) _ = if (sobj==cld) then fds else getServerObjectScalars sobj t []
+
+-- BASIC
+getIntersection :: Eq a => [[a]] -> [a]
+getIntersection [] = []
+getIntersection ([]:t) = []
+getIntersection ((h:t1):t2) = if (foldr (\x y -> (elem h x)&&y) True t2) then (h:(getIntersection (t1:t2))) else (getIntersection (t1:t2))
+
+getParentObjects :: [String] -> [(String,[String])] -> [String]
+getParentObjects cdn sos = getIntersection $ getChildrenObjects cdn sos
+getChildrenObjects :: [String] -> [(String,[String])] -> [[String]]
+getChildrenObjects [] _ = []
+getChildrenObjects (h:t) sos = (getChildObjects h sos):(getChildrenObjects t sos)
+getChildObjects :: String -> [(String,[String])] -> [String]
+getChildObjects _ [] = []
+getChildObjects cld ((so,obs):t) = if cld==so then obs++(getChildObjects cld t) else getChildObjects cld t
+isServerObjectTable :: String -> ServerObject -> [(String,String)] -> [(String,[String],[String])] -> Bool
+isServerObjectTable tbl soj sodn soa = elem tbl $ translateServerObjectToDBName soj sodn soa
src/Components/ObjectHandlers/ServerObjectTrimmer.hs view
@@ -1,10 +1,35 @@ module Components.ObjectHandlers.ServerObjectTrimmer (mergeDuplicatedRootObjects) where
 
-import Data.Either
-import qualified Control.Exception as E
-import Model.ServerObjectTypes
-import Model.ServerExceptions
-import Components.ObjectHandlers.ObjectsHandler
+import Model.ServerObjectTypes (
+    RootObject,
+    RootObjects,
+    NestedObject(..),
+    ScalarType,
+    Field,
+    FieldObject,
+    InlinefragmentObject(..)
+  )
+import Model.ServerExceptions (
+    QueryException(
+      InvalidObjectException,
+      InvalidScalarException,
+      DuplicateRootObjectsException,
+      FailedObjectEqualityException
+    )
+  )
+import Components.ObjectHandlers.ObjectsHandler (
+    isSameNObjectReference,
+    isSameIFObjectReference,
+    isSameObjectSubSelection
+  )
+import Data.Either (
+    fromLeft,
+    fromRight,
+    isLeft,
+    isRight,
+    Either(Left,Right)
+  )
+import Control.Exception (throw)
 
 
 mergeDuplicatedRootObjects :: [RootObject] -> [RootObject]
@@ -22,8 +47,8 @@ separateDuplicatesAndDifferencesHelper :: RootObject -> [RootObject] -> [RootObject] -> [RootObject] -> ([RootObject],[RootObject])
 separateDuplicatesAndDifferencesHelper robj [] dup diff = (dup,diff)
 separateDuplicatesAndDifferencesHelper robj (h:t) dup diff
-   | (isSameObjectReference robj h)&&(isSameObjectSubSelection robj h) = separateDuplicatesAndDifferencesHelper robj t (h:dup) diff
-   | (isSameObjectReference robj h) = E.throw DuplicateRootObjectsException
+   | (isSameNObjectReference robj h)&&(isSameObjectSubSelection robj h) = separateDuplicatesAndDifferencesHelper robj t (h:dup) diff
+   | (isSameNObjectReference robj h) = throw DuplicateRootObjectsException
    | otherwise = separateDuplicatesAndDifferencesHelper robj t dup (h:diff)
 -- merge together valid (same referene and same subselection) RootObjects
 mergeDuplicates :: RootObject -> [RootObject] -> RootObject
@@ -36,36 +61,48 @@ compressSubSelections :: [Field] -> [Field]
 compressSubSelections [] = []
 compressSubSelections lst = compressSubSelectionsHelper lst []
--- We want a removed-duplicate set with a list of Fields, and empty list/.
+-- We want a removed-duplicate set with a list of Fields, and empty list.
 compressSubSelectionsHelper :: [Field] -> [Field] -> [Field]
 compressSubSelectionsHelper [] rst = rst
 compressSubSelectionsHelper (h:t) rst
     | (isLeft h) = compressSubSelectionsHelper t (combineScalarTypeWithPresent rst st)
-    | otherwise = compressSubSelectionsHelper t (combineNestedObjectWithPresent rst no)
+    | otherwise = compressSubSelectionsHelper t (combineFieldObjectWithPresent rst fo)
   where
-    st = (fromLeft (E.throw InvalidScalarException) h)
-    no = (fromRight (E.throw InvalidObjectException) h)
+    st = (fromLeft (throw InvalidScalarException) h)
+    fo = (fromRight (throw InvalidObjectException) h)
 -- with two sets of fields, we want a union that is no duplicates
 mergeFields :: [Field] -> [Field] -> [Field]
 mergeFields lst [] = lst
 mergeFields lst (h:t)
-    | (isLeft h)==True = mergeFields (combineScalarTypeWithPresent lst (fromLeft (E.throw InvalidScalarException) h)) t
-    | otherwise = mergeFields (combineNestedObjectWithPresent lst (fromRight (E.throw InvalidObjectException) h)) t
+    | (isLeft h)==True = mergeFields (combineScalarTypeWithPresent lst (fromLeft (throw InvalidScalarException) h)) t
+    | otherwise = mergeFields (combineFieldObjectWithPresent lst (fromRight (throw InvalidObjectException) h)) t
 -- with list of Field and one ScalarType, we want a union set of list and new ScalarType
 combineScalarTypeWithPresent :: [Field] -> ScalarType -> [Field]
 combineScalarTypeWithPresent [] st = (Left st):[]
 combineScalarTypeWithPresent (h:t) st
-    | (isLeft h)&&(fromLeft (E.throw InvalidScalarException) h)==st = h:t
+    | (isLeft h)&&(fromLeft (throw InvalidScalarException) h)==st = h:t
     | otherwise = h:(combineScalarTypeWithPresent t st)
 -- with list of Field and one NestedObject, we want a union set of list and new NestedObject
-combineNestedObjectWithPresent :: [Field] -> NestedObject -> [Field]
-combineNestedObjectWithPresent [] no = (Right no):[]
-combineNestedObjectWithPresent (h:t) no
-    | (isRight h)&&(isSameObjectReference nobj no)&&(isSameObjectSubSelection nobj no) = (Right $ mergeObjects nobj no):t
-    | (isRight h)&&(isSameObjectReference nobj no) = E.throw DuplicateRootObjectsException
-    | otherwise = h:(combineNestedObjectWithPresent t no)
+combineFieldObjectWithPresent :: [Field] -> FieldObject -> [Field]
+combineFieldObjectWithPresent [] fo = (Right fo):[]
+combineFieldObjectWithPresent (h:t) fo
+    | (isLeft h) = h:(combineFieldObjectWithPresent t fo)
+    | (isLeft fobj)&&(isRight fo) = h:(combineFieldObjectWithPresent t fo)
+    | (isLeft fo)&&(isRight fobj) = h:(combineFieldObjectWithPresent t fo)
+    | (isLeft fobj)&&(isSameNObjectReference nobj lnobj)&&(isSameObjectSubSelection nobj lnobj) = (Right $ Left $ mergeNObjects nobj lnobj):t
+    | (isLeft fobj)&&(isSameNObjectReference nobj lnobj) = throw DuplicateRootObjectsException
+    | (isLeft fobj) = h:(combineFieldObjectWithPresent t fo)
+    | (isSameIFObjectReference ifobj lifobj) = (Right $ Right $ mergeIFObjects ifobj lifobj):t
+    | otherwise = h:(combineFieldObjectWithPresent t fo)
   where
-    nobj = (fromRight (E.throw InvalidObjectException) h)
--- we want one NestedObject that is same reference, same SubSelection and union set subfields with two NestObjects that are same reference (alias, name, and ServerObject) and same SubSelection.
-mergeObjects :: NestedObject -> NestedObject -> NestedObject
-mergeObjects (NestedObject alias1 name1 sobj1 ss1 sfs1) (NestedObject alias2 name2 sobj2 ss2 sfs2) = if (alias1==alias2&&name1==name2&&sobj1==sobj2&&ss1==ss2) then (NestedObject alias1 name1 sobj1 ss1 (mergeFields sfs1 sfs2)) else (E.throw FailedObjectEqualityException)+    fobj = fromRight (throw InvalidObjectException) h
+    lnobj = fromLeft (throw InvalidObjectException) fobj
+    lifobj = fromRight (throw InvalidObjectException) fobj
+    nobj = fromLeft (throw InvalidObjectException) fo
+    ifobj = fromRight (throw InvalidObjectException) fo
+-- we want one NestedObject that is same reference, same SubSelection and union set subfields with two NestedObjects that are same reference (alias, name, and ServerObject) and same SubSelection.
+mergeNObjects :: NestedObject -> NestedObject -> NestedObject
+mergeNObjects (NestedObject alias1 name1 sobj1 ss1 sfs1) (NestedObject alias2 name2 sobj2 ss2 sfs2) = if (alias1==alias2&&name1==name2&&sobj1==sobj2&&ss1==ss2) then (NestedObject alias1 name1 sobj1 ss1 (mergeFields sfs1 sfs2)) else (throw FailedObjectEqualityException)
+-- we want one InlinefragmentObject that is same ServerObject and is union set subfields with two InlinefragmentObjects that are same reference (ServerObject)
+mergeIFObjects :: InlinefragmentObject -> InlinefragmentObject -> InlinefragmentObject
+mergeIFObjects (InlinefragmentObject sobj1 sfs1) (InlinefragmentObject sobj2 sfs2) = if (sobj1==sobj2) then (InlinefragmentObject sobj1 (mergeFields sfs1 sfs2)) else (throw FailedObjectEqualityException)
src/Components/ObjectHandlers/ServerObjectValidator.hs view
@@ -1,31 +1,52 @@ module Components.ObjectHandlers.ServerObjectValidator (checkObjectsAttributes,replaceObjectsVariables) where
 
-import qualified Control.Exception as E
-import Data.Maybe
-import Data.Either
-import Model.ServerObjectTypes
-import Model.ServerExceptions
-import Components.ObjectHandlers.ObjectsHandler
 
+import Model.ServerObjectTypes (
+        ServerObject,
+        RootObject,
+        ScalarType(..),
+        SubSelection,
+        Field,
+        FieldObject,
+        InlinefragmentObject(..),
+        NestedObject(..)
+    )
+import Model.ServerExceptions (
+        QueryException(
+            InvalidObjectException,
+            InvalidVariableNameException,
+            InvalidObjectScalarFieldException,
+            MismatchedVariableTypeException
+        )
+    )
+import Components.ObjectHandlers.ObjectsHandler (
+        getObjectName,
+        getInlinefragmentFields,
+        getInlinefragmentObject,
+        isValidServerObjectChild,
+        isValidServerObjectNestedObjectField,
+        getScalarName,
+        isValidServerObjectScalarField
+    )
+import Control.Exception (throw)
+import Data.Maybe (fromJust,Maybe(Just,Nothing))
+import Data.Either (Either(Right,Left))
 
 -- check that all nested objects are with valid properties
-checkObjectsAttributes :: [RootObject] -> [(String,[(String,String)])] -> [(String,[String])] -> Bool
-checkObjectsAttributes objs sss sos = foldr (\x y -> (hasValidAttributes x sss sos)&&y) True objs
-hasValidAttributes :: NestedObject -> [(String,[(String,String)])] -> [(String,[String])] -> Bool
-hasValidAttributes (NestedObject alias name sobject ss sfs) sss sos = (if ss==Nothing then True else isValidSubSelection sobject (fromJust ss) sss)&&(isValidSubFields sobject sfs sss sos)
-isValidSubSelection :: ServerObject -> ScalarType -> [(String,[(String,String)])] -> Bool
-isValidSubSelection obj (ScalarType alias name trans arg) sss = (isValidServerObjectScalarField obj name sss)  -- &&(isValidScalarTransformation obj name trans arg)
-isValidSubFields :: ServerObject -> [Field] -> [(String,[(String,String)])] -> [(String,[String])] -> Bool
-isValidSubFields _ [] _ _ = True  -- we should not get an empty query
-isValidSubFields obj sfs sss sos = foldr (\x y -> (isValidSubField obj x sss sos)&&y) True sfs
-isValidSubField :: ServerObject -> Field -> [(String,[(String,String)])]-> [(String,[String])] -> Bool
-isValidSubField obj (Left sf) sss sos = (isValidServerObjectScalarField obj sname sss)  -- &&(isValidScalarTransformation obj sname trans arg)
-  where
-    sname = getScalarName sf
-isValidSubField obj sf sss sos = (isValidServerObjectNestedObjectField obj ofname sos)&&(hasValidAttributes nestedObjectField sss sos)
-  where
-    nestedObjectField = fromRight (E.throw InvalidObjectException) sf
-    ofname = getObjectName nestedObjectField
+checkObjectsAttributes :: [RootObject] -> [(String,[(String,String)])] -> [(String,[String])] -> [(String,[String],[String])] -> Bool
+checkObjectsAttributes objs sss sos soa = foldr (\x y -> (hasValidAttributes x sss sos soa)&&y) True objs
+hasValidAttributes :: NestedObject -> [(String,[(String,String)])] -> [(String,[String])] -> [(String,[String],[String])] -> Bool
+hasValidAttributes (NestedObject alias name sobject ss sfs) sss sos soa = (if ss==Nothing then True else isValidSubSelection sobject (fromJust ss) sss soa)&&(isValidSubFields sobject sfs sss sos soa)
+isValidSubSelection :: ServerObject -> ScalarType -> [(String,[(String,String)])] -> [(String,[String],[String])] -> Bool
+isValidSubSelection obj (ScalarType alias name trans arg) sss soa = (isValidServerObjectScalarField obj name sss soa)  -- &&(isValidScalarTransformation obj name trans arg)
+isValidSubFields :: ServerObject -> [Field] -> [(String,[(String,String)])] -> [(String,[String])] -> [(String,[String],[String])] -> Bool
+isValidSubFields _ [] _ _ _ = True  -- we should not get an empty query
+isValidSubFields obj sfs sss sos soa = foldr (\x y -> (isValidSubField obj x sss sos soa)&&y) True sfs
+isValidSubField :: ServerObject -> Field -> [(String,[(String,String)])]-> [(String,[String])] -> [(String,[String],[String])] -> Bool
+isValidSubField obj (Left sf) sss sos soa = (isValidServerObjectScalarField obj (getScalarName sf) sss soa)  -- &&(isValidScalarTransformation obj sname trans arg)
+isValidSubField obj (Right (Left no)) sss sos soa = (isValidServerObjectNestedObjectField obj (getObjectName no) sos soa)&&(hasValidAttributes no sss sos soa)
+isValidSubField obj (Right (Right ifo)) sss sos soa = (isValidServerObjectChild obj soj soa)&&(isValidSubFields soj (getInlinefragmentFields ifo) sss sos soa)
+                                                      where soj = getInlinefragmentObject ifo
 -- replace variables with values and do type checking
 -- ASSUME: variables are prefixed with $
 replaceObjectsVariables :: [(String,[(String,String)])] -> [RootObject] -> [(String,String,String)] -> [RootObject]
@@ -34,22 +55,23 @@ replaceObjectVariables :: [(String,[(String,String)])] -> RootObject -> [(String,String,String)] -> RootObject
 replaceObjectVariables sss (NestedObject alias name sobject ss sfs) vars = NestedObject alias name sobject (if ss/=Nothing then (replaceScalarVariable (findScalars sss sobject) vars $ fromJust ss) else Nothing) [replaceSubfieldVariables sss sobject vars sf | sf<-sfs]
 findScalars :: [(String,[(String,String)])] -> String -> [(String,String)]
-findScalars [] _ = E.throw InvalidObjectException
+findScalars [] _ = throw InvalidObjectException
 findScalars ((name,sclrs):t) sobj = if (sobj==name) then sclrs else (findScalars t sobj)
 replaceScalarVariable :: [(String,String)] -> [(String,String,String)] -> ScalarType -> SubSelection
 replaceScalarVariable sclrs vars (ScalarType alias name trans arg) = if (isValue arg)&&(elem '$' $ getValue arg) then (Just $ ScalarType alias name trans (Just $ findReplacement (findScalarType sclrs name) (getValue arg) vars)) else (Just $ ScalarType alias name trans arg)
 findScalarType :: [(String,String)] -> String -> String
-findScalarType [] _ = E.throw InvalidObjectScalarFieldException
+findScalarType [] _ = throw InvalidObjectScalarFieldException
 findScalarType ((name,typ):t) sname = if sname==name then typ else (findScalarType t sname) 
 findReplacement :: String -> String -> [(String,String,String)] -> String
-findReplacement styp arg [] = E.throw InvalidVariableNameException
+findReplacement styp arg [] = throw InvalidVariableNameException
 findReplacement styp arg ((name,typ,val):t)
     | (name==arg)&&(typ==styp) = val
-    | (name==arg) = E.throw MismatchedVariableTypeException
+    | (name==arg) = throw MismatchedVariableTypeException
     | otherwise = findReplacement styp arg t
 replaceSubfieldVariables :: [(String,[(String,String)])] -> String -> [(String,String,String)] -> Field -> Field
-replaceSubfieldVariables sss sobj vars (Right (NestedObject alias name nsobj ss sfs)) = (Right $ NestedObject alias name nsobj (if ss/=Nothing then (replaceScalarVariable (findScalars sss nsobj) vars $ fromJust ss) else Nothing) [replaceSubfieldVariables sss nsobj vars sf | sf<-sfs]) :: Field
 replaceSubfieldVariables sss sobj vars (Left (ScalarType alias name trans arg)) = if (isValue arg)&&(elem '$' $ getValue arg) then (Left (ScalarType alias name trans (Just $ findReplacement (findScalarType (findScalars sss sobj) name) (getValue arg) vars)) :: Field) else (Left (ScalarType alias name trans arg) :: Field)
+replaceSubfieldVariables sss sobj vars (Right (Left (NestedObject alias name nsobj ss sfs))) = (Right (Left $ NestedObject alias name nsobj (if ss/=Nothing then (replaceScalarVariable (findScalars sss nsobj) vars $ fromJust ss) else Nothing) [replaceSubfieldVariables sss nsobj vars sf | sf<-sfs] :: FieldObject) :: Field)
+replaceSubfieldVariables sss sobj vars (Right (Right (InlinefragmentObject ifsobj sfs))) = (Right (Right $ InlinefragmentObject ifsobj [replaceSubfieldVariables sss ifsobj vars sf | sf<-sfs] :: FieldObject) :: Field)
 isValue :: Maybe String -> Bool
 isValue Nothing = False
 isValue _ = True
src/Components/Parsers/QueryParser.hs view
@@ -1,10 +1,34 @@ module Components.Parsers.QueryParser (processString,validateQuery,parseStringToObjects) where
 
-
-import qualified Control.Exception as E
-import Model.ServerExceptions
-import Model.ServerObjectTypes
+import Model.ServerExceptions (
+        QueryException(
+            SyntaxException,
+            InvalidScalarException,
+            InvalidObjectException,
+            InvalidVariableNameException,
+            EmptyQueryException,
+            ParseFragmentException,
+            MismatchedVariableTypeException
+        )
+    )
+import Model.ServerObjectTypes (
+        NestedObject(..),
+        ServerObject,
+        Alias,
+        Argument,
+        Transformation,
+        ScalarType(..),
+        RootObjects,
+        RootObject,
+        Name,
+        SubFields,
+        InlinefragmentObject(..),
+        Field,
+        FieldObject,
+        SubSelection
+    )
 import Components.ObjectHandlers.ObjectsHandler (readServerObject)
+import Control.Exception (throw)
 import Data.Char (toLower)
 
 
@@ -17,25 +41,19 @@ removeCommentsHelper :: String -> Bool -> String
 removeCommentsHelper [] _ = []
 removeCommentsHelper (h:[]) _ = h:[]
-removeCommentsHelper (h1:h2:t) mde
- | h1=='#' = removeCommentsHelper (h2:t) True
- | h1=='\r' = '\r':removeCommentsHelper (h2:t) False
- | h1=='\n' = '\n':removeCommentsHelper (h2:t) False
- | h1=='\\'&&h2=='r' = '\\':'r':removeCommentsHelper t False
- | h1=='\\'&&h2=='n' = '\\':'n':removeCommentsHelper t False
- | mde==True = removeCommentsHelper (h2:t) mde
- | otherwise = h1:(removeCommentsHelper (h2:t) mde)
+removeCommentsHelper (h:t) mde
+ | h=='#' = removeCommentsHelper t True
+ | h=='\r' = '\r':removeCommentsHelper t False
+ | h=='\n' = '\n':removeCommentsHelper t False
+ | mde==True = removeCommentsHelper t mde
+ | otherwise = h:(removeCommentsHelper t mde)
 -- NOTE: this is used with only the textarea field of forms since they are giving line breaks these combinations...
 removeLinebreaks :: String -> String
 removeLinebreaks [] = []
-removeLinebreaks (h:[])
- | h=='\n'   = ' ':[]
- | h=='\r'   = ' ':[]
- | otherwise = h:[]
-removeLinebreaks (h1:h2:t)
- | h1=='\\'&&h2=='r' = ' ':removeLinebreaks t
- | h1=='\\'&&h2=='n' = ' ':removeLinebreaks t
- | otherwise = h1:removeLinebreaks (h2:t)
+removeLinebreaks (h:t)
+ | h=='\n'   = ' ':removeLinebreaks t
+ | h=='\r'   = ' ':removeLinebreaks t
+ | otherwise = h:removeLinebreaks t
 
 
 {-----Step 2. VALIDATION-----}
@@ -71,13 +89,13 @@ 
 
 {-----Step 3. PARSING-----}
-parseStringToObjects :: String -> [(String,[String])] -> [(String,String,String)] -> RootObjects
-parseStringToObjects [] _ _ = E.throw EmptyQueryException
-parseStringToObjects str svrobjs vars = composeObjects query svrobjs vars
+parseStringToObjects :: String -> [(String,[String])] -> [(String,[String],[String])] -> [(String,String,String)] -> RootObjects
+parseStringToObjects [] _ _ _ = throw EmptyQueryException
+parseStringToObjects str svrobjs soa vars = composeObjects qry svrobjs soa vars fragments
   where
     (qry,fmts) = getQueryAndFragments str
-    fragments = parseFragments fmts svrobjs
-    query = substituteFragments qry fragments svrobjs vars
+    fragments = parseFragments fmts svrobjs soa
+    -- query = substituteFragments qry fragments svrobjs vars
 -- REQUIRES: curly braces are in correct order
 getQueryAndFragments :: String -> (String, String)
 getQueryAndFragments str = getQueryAndFragmentsHelper str 0 False "" ""
@@ -94,98 +112,60 @@     , targetObject :: ServerObject
     , replacement :: String
     } deriving Show
-parseFragments :: String -> [(String,[String])] -> [Fragment]
-parseFragments str svrobjs = parseFragmentsHelper str "" 0 [] svrobjs
-parseFragmentsHelper :: String -> String -> Int -> [Fragment] -> [(String,[String])] -> [Fragment]
-parseFragmentsHelper [] _ _ rslt _ = rslt
-parseFragmentsHelper (h:t) acc l rslt svrobjs
- | h=='{' = parseFragmentsHelper t (acc++[h]) (l+1) rslt svrobjs
- | h=='}'&&l==1 = parseFragmentsHelper t [] (l-1) ((createFragment acc svrobjs):rslt) svrobjs -- completed one fragment
- | h=='}' = parseFragmentsHelper t (acc++[h]) (l-1) rslt svrobjs  -- closed a nested object
- | otherwise = parseFragmentsHelper t (acc++[h]) l rslt svrobjs
+parseFragments :: String -> [(String,[String])] -> [(String,[String],[String])] -> [Fragment]
+parseFragments str svrobjs soa = parseFragmentsHelper str "" 0 [] svrobjs soa
+parseFragmentsHelper :: String -> String -> Int -> [Fragment] -> [(String,[String])] -> [(String,[String],[String])] -> [Fragment]
+parseFragmentsHelper [] _ _ rslt _ _ = rslt
+parseFragmentsHelper (h:t) acc l rslt svrobjs soa
+ | h=='{' = parseFragmentsHelper t (acc++[h]) (l+1) rslt svrobjs soa
+ | h=='}'&&l==1 = parseFragmentsHelper t [] (l-1) ((createFragment acc svrobjs soa):rslt) svrobjs soa -- completed one fragment
+ | h=='}' = parseFragmentsHelper t (acc++[h]) (l-1) rslt svrobjs soa  -- closed a nested object
+ | otherwise = parseFragmentsHelper t (acc++[h]) l rslt svrobjs soa
 -- with a fragment string that is without closing curly braces, we want a fragments
-createFragment :: String -> [(String,[String])] -> Fragment
-createFragment str svrobjs = createFragmentHelper str 0 [] False False False False "" "" svrobjs
+createFragment :: String -> [(String,[String])] -> [(String,[String],[String])] -> Fragment
+createFragment str svrobjs soa = createFragmentHelper str 0 [] False False False False "" "" svrobjs soa
 {-
     d is for declaration
     n is for name
     a is for arrangement
     o is for object
 -}
-createFragmentHelper :: String -> Int -> String -> Bool -> Bool -> Bool -> Bool -> String -> String -> [(String,[String])] -> Fragment
-createFragmentHelper [] l acc d n a o rst1 rst2 svrobjs = if (l==1&&d==True&&n==True&&a==True&&o==True) then Fragment { name=rst1,targetObject=(readServerObject rst2 svrobjs),replacement=acc } else E.throw ParseFragmentException
-createFragmentHelper (h:t) l acc d n a o rst1 rst2 svrobjs
- | d==False&&(h=='f'||h=='r'||h=='a'||h=='g'||h=='m'||h=='e'||h=='n'||h=='t') = createFragmentHelper t l (acc++[h]) d n a o rst1 rst2 svrobjs
- | d==False&&h==' '&&(length acc)>0&&acc=="fragment" = createFragmentHelper t l [] True n a o rst1 rst2 svrobjs
- | d==False&&h==' '&&(length acc)>0 = E.throw ParseFragmentException
- | d==False&&h==' '&&(length acc)<1 = createFragmentHelper t l [] d n a o rst1 rst2 svrobjs
- | d==False = E.throw ParseFragmentException
- | n==False&&h==' '&&(length acc)==0 = createFragmentHelper t l [] d n a o rst1 rst2 svrobjs
- | n==False&&h==' '&&(length acc)>0 = createFragmentHelper t l [] d True a o acc rst2 svrobjs
- | n==False&&(isValidFragmentNameChar h)==False = E.throw ParseFragmentException
- | n==False = createFragmentHelper t l (acc++[h]) d n a o rst1 rst2 svrobjs
- | a==False&&h==' '&&(length acc)==0 = createFragmentHelper t l [] d n a o rst1 rst2 svrobjs
- | a==False&&h==' '&&(length acc)>0&&(acc=="on") = createFragmentHelper t l [] d n True o rst1 rst2 svrobjs
- | a==False&&h==' '&&(length acc)>0 = E.throw ParseFragmentException
- | a==False&&(h=='o'||h=='n') = createFragmentHelper t l (acc++[h]) d n a o rst1 rst2 svrobjs
- | a==False = E.throw ParseFragmentException
- | o==False&&((length acc)==0)&&((fromEnum h)>=97||(fromEnum h)<=122) = createFragmentHelper t l (acc++[h]) d n a o rst1 rst2 svrobjs
- | o==False&&((length acc)==0)&&(h==' ') = createFragmentHelper t l [] d n a o rst1 rst2 svrobjs
- | o==False&&((length acc)==0) = E.throw ParseFragmentException
- | o==False&&h==' ' = createFragmentHelper t l [] d n a True rst1 acc svrobjs
- | o==False&&h=='{' = createFragmentHelper t (l+1) [] d n a True rst1 acc svrobjs
- | o==False&&(isValidIdentifierChar h) = createFragmentHelper t l (acc++[h]) d n a o rst1 rst2 svrobjs
- | o==False = E.throw ParseFragmentException
- | h==' '&&l==0 = createFragmentHelper t l [] d n a o rst1 rst2 svrobjs
- | h=='{'&&l==0 = createFragmentHelper t (l+1) [] d n a o rst1 rst2 svrobjs
- | l==0 = E.throw ParseFragmentException
- | (isValidIdentifierChar h)||h==' '||h==')'||h=='('||h==':'||h=='$'||h=='@' = createFragmentHelper t l (acc++[h]) d n a o rst1 rst2 svrobjs
- | h=='{' = createFragmentHelper t (l+1) (acc++[h]) d n a o rst1 rst2 svrobjs
- | h=='}' = createFragmentHelper t (l-1) (acc++[h]) d n a o rst1 rst2 svrobjs
- | otherwise = E.throw ParseFragmentException
+createFragmentHelper :: String -> Int -> String -> Bool -> Bool -> Bool -> Bool -> String -> String -> [(String,[String])] -> [(String,[String],[String])] -> Fragment
+createFragmentHelper [] l acc d n a o rst1 rst2 svrobjs soa = if (l==1&&d==True&&n==True&&a==True&&o==True) then Fragment { name=rst1,targetObject=(readServerObject rst2 svrobjs soa),replacement=acc } else throw ParseFragmentException
+createFragmentHelper (h:t) l acc d n a o rst1 rst2 svrobjs soa
+ | d==False&&(h=='f'||h=='r'||h=='a'||h=='g'||h=='m'||h=='e'||h=='n'||h=='t') = createFragmentHelper t l (acc++[h]) d n a o rst1 rst2 svrobjs soa
+ | d==False&&h==' '&&(length acc)>0&&acc=="fragment" = createFragmentHelper t l [] True n a o rst1 rst2 svrobjs soa
+ | d==False&&h==' '&&(length acc)>0 = throw ParseFragmentException
+ | d==False&&h==' '&&(length acc)<1 = createFragmentHelper t l [] d n a o rst1 rst2 svrobjs soa
+ | d==False = throw ParseFragmentException
+ | n==False&&h==' '&&(length acc)==0 = createFragmentHelper t l [] d n a o rst1 rst2 svrobjs soa
+ | n==False&&h==' '&&(length acc)>0 = createFragmentHelper t l [] d True a o acc rst2 svrobjs soa
+ | n==False&&(isValidFragmentNameChar h)==False = throw ParseFragmentException
+ | n==False = createFragmentHelper t l (acc++[h]) d n a o rst1 rst2 svrobjs soa
+ | a==False&&h==' '&&(length acc)==0 = createFragmentHelper t l [] d n a o rst1 rst2 svrobjs soa
+ | a==False&&h==' '&&(length acc)>0&&(acc=="on") = createFragmentHelper t l [] d n True o rst1 rst2 svrobjs soa
+ | a==False&&h==' '&&(length acc)>0 = throw ParseFragmentException
+ | a==False&&(h=='o'||h=='n') = createFragmentHelper t l (acc++[h]) d n a o rst1 rst2 svrobjs soa
+ | a==False = throw ParseFragmentException
+ | o==False&&((length acc)==0)&&((fromEnum h)>=97||(fromEnum h)<=122) = createFragmentHelper t l (acc++[h]) d n a o rst1 rst2 svrobjs soa
+ | o==False&&((length acc)==0)&&(h==' ') = createFragmentHelper t l [] d n a o rst1 rst2 svrobjs soa
+ | o==False&&((length acc)==0) = throw ParseFragmentException
+ | o==False&&h==' ' = createFragmentHelper t l [] d n a True rst1 acc svrobjs soa
+ | o==False&&h=='{' = createFragmentHelper t (l+1) [] d n a True rst1 acc svrobjs soa
+ | o==False&&(isValidIdentifierChar h) = createFragmentHelper t l (acc++[h]) d n a o rst1 rst2 svrobjs soa
+ | o==False = throw ParseFragmentException
+ | h==' '&&l==0 = createFragmentHelper t l [] d n a o rst1 rst2 svrobjs soa
+ | h=='{'&&l==0 = createFragmentHelper t (l+1) [] d n a o rst1 rst2 svrobjs soa
+ | l==0 = throw ParseFragmentException
+ | (isValidIdentifierChar h)||h==' '||h==')'||h=='('||h==':'||h=='$'||h=='@' = createFragmentHelper t l (acc++[h]) d n a o rst1 rst2 svrobjs soa
+ | h=='{' = createFragmentHelper t (l+1) (acc++[h]) d n a o rst1 rst2 svrobjs soa
+ | h=='}' = createFragmentHelper t (l-1) (acc++[h]) d n a o rst1 rst2 svrobjs soa
+ | otherwise = throw ParseFragmentException
 isValidFragmentNameChar :: Char -> Bool
 isValidFragmentNameChar c = ((fromEnum c)>=65&&(fromEnum c)<=90)||((fromEnum c)>=97&&(fromEnum c)<=122)||((fromEnum c)>=48&&(fromEnum c)<=57)||((fromEnum c)==95)
 isValidIdentifierChar :: Char -> Bool
 isValidIdentifierChar c = ((fromEnum c)>=65&&(fromEnum c)<=90)||((fromEnum c)>=97&&(fromEnum c)<=122)||((fromEnum c)>=48&&(fromEnum c)<=57)||((fromEnum c)==95)||((fromEnum c)==39)
- -- call after infering types on nested objects
-substituteFragments :: String -> [Fragment] -> [(String,[String])] -> [(String,String,String)] -> String
-substituteFragments [] _ _ _ = ""
-substituteFragments str [] _ _ = str
--- check that all fragments are valid
-substituteFragments str fragments svrobjs vars = substituteFragmentsHelper str fragments 0 "" svrobjs vars
--- With query code, we use fragments to replace code blocks
--- REQUIRES: the curly braces are correctly balanced and placed
-substituteFragmentsHelper :: String -> [Fragment] -> Int -> String -> [(String,[String])] -> [(String,String,String)] -> String
-substituteFragmentsHelper [] _ _ _ _ _ = ""
-substituteFragmentsHelper str [] _ _ _ _ = str
-substituteFragmentsHelper (h:t) fragments l acc svrobjs vars
-    | h=='{'&&l==0 = h:substituteFragmentsHelper t fragments (l+1) [] svrobjs vars
-    | l==0 = h:substituteFragmentsHelper t fragments l [] svrobjs vars
-    | h=='{' = ((h:(subResult))++(substituteFragmentsHelper continue fragments (l+1) [] svrobjs vars))
-    | h=='}' = h:(substituteFragmentsHelper t fragments (l-1) [] svrobjs vars)
-    | otherwise = h:(substituteFragmentsHelper t fragments l (acc++[h]) svrobjs vars)
-  where
-    replacer = findFragment fragments (getNestedObject acc svrobjs)
-    (subject, continue) = splitSubject t "" 0
-    subResult = substituteHelper subject (target replacer) (switch replacer) "" "" vars
--- from accumulated objects/fields/arguments, we return a found object where code is without brackets
-getNestedObject :: String -> [(String,[String])] -> ServerObject
-getNestedObject [] _ = E.throw ParseFragmentException
-getNestedObject str svrobjs
-    | (elem ':' str)&&(elem '(' str) = readServerObject (removeSpaces $ foldl (\y x -> if x==':' then [] else y++[x]) "" (foldr (\x y -> if x=='(' then [] else x:y) "" str)) svrobjs
-    | (elem '(' str) = readServerObject (removeSpaces $ foldr (\x y -> if x=='(' then [] else x:y) "" str) svrobjs
-    | (elem ':' str) = readServerObject (removeSpaces $ foldl (\y x -> if x==':' then [] else y++[x]) "" str) svrobjs
-    | otherwise = readServerObject (removeSpaces str) svrobjs
--- from possible fragments and found fragment (if present), we return (replacement string, target string).
-data Replacer = Replacer
-    { target :: String
-    , switch :: String
-    }
-findFragment :: [Fragment] -> ServerObject -> Replacer
-findFragment [] _ = Replacer { target="",switch="" }  -- we never encounter an empty Fragment list, so we needn't worry about a blank Replacer
-findFragment (frt:t) tar
- | (targetObject frt)==tar = Replacer { target=("..."++(name frt)),switch=(replacement frt) }
- | otherwise = findFragment t tar
+--  -- call after infering types on nested objects
 -- get block in this scope
 splitSubject :: String -> String -> Int -> (String,String)
 splitSubject [] acc _ = (acc,"")
@@ -194,22 +174,7 @@  | h=='{' = splitSubject t (acc++[h]) (l+1)
  | h=='}' = splitSubject t (acc++[h]) (l-1)
  | otherwise = splitSubject t (acc++[h]) l
--- substitute target string with replacement string within subject string...return result
-substituteHelper :: String -> String -> String -> String -> String -> [(String,String,String)] -> String
-substituteHelper [] _ _ acc rlt _ = (rlt++acc)
-substituteHelper subj [] _ _ _ _ = subj
-substituteHelper (h:t) trg rpl acc rlt vars
-    | (length acc)<3&&h=='.' = substituteHelper t trg rpl (acc++[h]) rlt vars
-    | (length acc)<3 = substituteHelper t trg rpl [] (rlt++acc++[h]) vars
-    | (isMatching (acc++[h]) trg)&&((length (acc++[h]))==(length trg))&&(directive==True) = substituteHelper t trg rpl [] (rlt++rpl) vars
-    | (isMatching (acc++[h]) trg)&&((length (acc++[h]))==(length trg)) = substituteHelper directiveTail trg rpl [] rlt vars
-    | (isMatching (acc++[h]) trg) = substituteHelper t trg rpl (acc++[h]) rlt vars
-    | otherwise = substituteHelper t trg rpl [] (rlt++acc++[h]) vars
-  where
-    (directive,directiveTail) = checkDirective t vars
--- check whether both strings are thus far same
-isMatching :: String -> String -> Bool
-isMatching acc trg = foldr (\(x,y) z -> (x==y)&&z) True (zip acc trg)
+-- -- substitute target string with replacement string within subject string...return result
 -- parse provided string to obtain query
 {-
 REQUIRES: Query is balanced and ordered brackets.
@@ -218,14 +183,14 @@ passing code block to separateRootObjects() where code block is not including query opening and closing brackets
 TODO: change Bool to Either with exceptions
 -}
-composeObjects :: String -> [(String,[String])] -> [(String,String,String)] -> RootObjects
-composeObjects [] _ _ = E.throw EmptyQueryException
-composeObjects str svrobjs vars = composeObjectsHelper str 0 svrobjs vars
-composeObjectsHelper :: String -> Int -> [(String,[String])] -> [(String,String,String)] -> RootObjects
-composeObjectsHelper [] _ _ _ = E.throw EmptyQueryException
-composeObjectsHelper (h:t) l svrobjs vars
- | h=='{'&&l==0 = separateRootObjects (extractLevel t) svrobjs vars -- find and separate every root object
- | otherwise = composeObjectsHelper t l svrobjs vars
+composeObjects :: String -> [(String,[String])] -> [(String,[String],[String])] -> [(String,String,String)] -> [Fragment] -> RootObjects
+composeObjects [] _ _ _ _ = throw EmptyQueryException
+composeObjects str svrobjs soa vars fmts = composeObjectsHelper str 0 svrobjs soa vars fmts
+composeObjectsHelper :: String -> Int -> [(String,[String])] -> [(String,[String],[String])] -> [(String,String,String)] -> [Fragment] -> RootObjects
+composeObjectsHelper [] _ _ _ _ _ = throw EmptyQueryException
+composeObjectsHelper (h:t) l svrobjs soa vars fmts
+ | h=='{'&&l==0 = separateRootObjects (extractLevel t) svrobjs soa vars fmts -- find and separate every root object
+ | otherwise = composeObjectsHelper t l svrobjs soa vars fmts
 -- ...separate and determine operation
 -- TODO: implement operations
 -- determineOperation :: String -> (Operation,String)
@@ -239,31 +204,33 @@ -- REQUIRES: brackets are balanced and ordered
 -- NOTE: only querying is first supported; mutations are later
 -- EFFECTS: passing block to createNestedObject where block is including opening and closing curly brackets
-separateRootObjects :: String -> [(String,[String])] -> [(String,String,String)] -> [RootObject]
-separateRootObjects str svrobjs vars = separateRootObjectsHelper str "" svrobjs vars
-separateRootObjectsHelper :: String -> String -> [(String,[String])] -> [(String,String,String)] -> [RootObject]
-separateRootObjectsHelper [] _ _ _ = []
-separateRootObjectsHelper (h:t) acc svrobjs vars
-    | h=='{' = (((createNestedObject (acc++[h]++level) svrobjs vars) :: RootObject):separateRootObjectsHelper levelTail "" svrobjs vars)
-    | otherwise = separateRootObjectsHelper t (acc++[h]) svrobjs vars
+separateRootObjects :: String -> [(String,[String])] -> [(String,[String],[String])] -> [(String,String,String)] -> [Fragment] -> [RootObject]
+separateRootObjects str svrobjs soa vars fmts = separateRootObjectsHelper str "" svrobjs soa vars fmts
+separateRootObjectsHelper :: String -> String -> [(String,[String])] -> [(String,[String],[String])] -> [(String,String,String)] -> [Fragment] -> [RootObject]
+separateRootObjectsHelper [] _ _ _ _ _ = []
+separateRootObjectsHelper (h:t) acc svrobjs soa vars fmts
+    | h=='{' = (((createNestedObject (acc++[h]++level) svrobjs soa vars fmts) :: RootObject):separateRootObjectsHelper levelTail "" svrobjs soa vars fmts)
+    | otherwise = separateRootObjectsHelper t (acc++[h]) svrobjs soa vars fmts
   where
     (level,levelTail) = splitLevel t "" 0
 -- create root object from block
 -- EFFECTS: passing code block to parseSubFields where block is not including root object opening and closing curly brackets.
-createNestedObject :: String -> [(String,[String])] -> [(String,String,String)] -> NestedObject
-createNestedObject str svrobjs vars = createNestedObjectHelper str "" svrobjs vars
-createNestedObjectHelper :: String -> String -> [(String,[String])] -> [(String,String,String)] -> NestedObject
-createNestedObjectHelper [] _ _ _ = E.throw InvalidObjectException  -- we should not encounter this since we already checked against empty brackets
-createNestedObjectHelper (h:t) acc svrobjs vars
- | h=='{' = (NestedObject ((parseAlias acc) :: Alias) ((parseName acc) :: Name) ((parseServerObject acc svrobjs) :: ServerObject) ((parseSubSelection acc) :: SubSelection) ((parseSubFields (extractLevel t) svrobjs vars) :: SubFields)) :: RootObject
- | otherwise = createNestedObjectHelper t (acc++[h]) svrobjs vars
+createNestedObject :: String -> [(String,[String])] -> [(String,[String],[String])] -> [(String,String,String)] -> [Fragment] -> NestedObject
+createNestedObject str svrobjs soa vars fmts = createNestedObjectHelper str "" svrobjs soa vars fmts
+createNestedObjectHelper :: String -> String -> [(String,[String])] -> [(String,[String],[String])] -> [(String,String,String)] -> [Fragment] -> NestedObject
+createNestedObjectHelper [] _ _ _ _ _ = throw InvalidObjectException  -- we should not encounter this since we already checked against empty brackets
+createNestedObjectHelper (h:t) acc svrobjs soa vars fmts
+    | h=='{' = (NestedObject ((parseAlias acc) :: Alias) ((parseName acc) :: Name) serverObj ((parseSubSelection acc) :: SubSelection) ((parseSubFields (extractLevel t) svrobjs soa vars fmts serverObj) :: SubFields)) :: RootObject
+    | otherwise = createNestedObjectHelper t (acc++[h]) svrobjs soa vars fmts
+  where
+    serverObj = ((parseServerObject acc svrobjs soa) :: ServerObject)
 -- given object header without any braces, we want a name.
-parseServerObject :: String -> [(String,[String])] -> ServerObject
-parseServerObject [] svrobjs = readServerObject "" svrobjs
-parseServerObject str svrobjs
- | (elem ':' str)==True&&(elem '(' str)==True = readServerObject (removeSpaces $ foldl (\y x -> if x==':' then [] else (y++[x])) "" (foldr (\x y -> if x=='(' then [] else x:y) "" str)) svrobjs
- | (elem ':' str)==True = readServerObject (removeSpaces $ foldl (\y x -> if x==':' then [] else (y++[x])) "" str) svrobjs
- | otherwise = readServerObject (removeSpaces str) svrobjs
+parseServerObject :: String -> [(String,[String])] -> [(String,[String],[String])] -> ServerObject
+parseServerObject [] svrobjs soa = readServerObject "" svrobjs soa
+parseServerObject str svrobjs soa
+ | (elem ':' str)==True&&(elem '(' str)==True = readServerObject (removeSpaces $ foldl (\y x -> if x==':' then [] else (y++[x])) "" (foldr (\x y -> if x=='(' then [] else x:y) "" str)) svrobjs soa
+ | (elem ':' str)==True = readServerObject (removeSpaces $ foldl (\y x -> if x==':' then [] else (y++[x])) "" str) svrobjs soa
+ | otherwise = readServerObject (removeSpaces str) svrobjs soa
 -- given object header without any braces, we want the alias if there is one.
 parseAlias :: String -> Alias
 parseAlias [] = Nothing :: Alias
@@ -271,17 +238,10 @@     | (elem ':' str)&&(elem '(' str) = parseAlias $ foldr (\x y -> if x=='(' then [] else x:y) "" str
     | (elem ':' str) = Just $ removeSpaces $ foldr (\x y -> if x==':' then [] else x:y) "" str
     | otherwise = Nothing :: Alias
--- parseAlias str = parseAliasHelper str ""
--- parseAliasHelper :: String -> String -> Alias
--- parseAliasHelper [] _ = Nothing :: Alias
--- parseAliasHelper (h:t) acc
---  | h=='(' = Nothing :: Alias
---  | h==':' = (Just $ removeSpaces acc) :: Alias
---  | otherwise = parseAliasHelper t (acc++[h])
 parseName :: String -> Name
-parseName [] = ""
+parseName [] = []
 parseName str
- | (elem ':' str)==True&&(elem '(' str)==True = removeSpaces $ foldl (\y x -> if x==':' then [] else (y++[x])) "" (foldr (\x y -> if x=='(' then [] else x:y) "" str)
+ | (elem ':' str)==True&&(elem '(' str)==True = removeSpaces $ foldl (\y x -> if x==':' then [] else (y++[x])) [] (foldr (\x y -> if x=='(' then [] else x:y) "" str)
  | (elem ':' str)==True = removeSpaces $ foldl (\y x -> if x==':' then [] else (y++[x])) "" str
  | otherwise = removeSpaces str
 parseSubSelection :: String -> SubSelection
@@ -290,42 +250,99 @@  | h=='('&&(elem ':' t)==True&&(elem ')' t)==True = Just (ScalarType (Nothing :: Alias) ((removeSideSpaces (foldr (\x y -> if x==':' then [] else x:y) "" t)) :: Name) (Nothing :: Transformation) ((Just $ removeSideSpaces $ foldl (\y x -> if x==':' then [] else (y++[x])) "" (foldr (\x y -> if x==')' then [] else x:y) "" t)) :: Argument)) :: SubSelection
  | otherwise = parseSubSelection t
 -- REQUIRES: code block on nested object subfields where nested object opening and closing curly brackets are not included
-parseSubFields :: String -> [(String,[String])] -> [(String,String,String)] -> [Field]
-parseSubFields [] _ _ = []
-parseSubFields str svrobjs vars = parseSubFieldsHelper str "" "" svrobjs True vars
-parseSubFieldsHelper :: String -> String -> String -> [(String,[String])] -> Bool -> [(String,String,String)] -> [Field]
-parseSubFieldsHelper [] [] [] _ _ _ = []
-parseSubFieldsHelper [] [] acc _ True _ = [Left $ createScalarType acc :: Field]
-parseSubFieldsHelper [] [] acc _ False _ = []
-parseSubFieldsHelper [] acc [] _ True _ = [Left $ createScalarType acc :: Field]
-parseSubFieldsHelper [] acc [] _ False _ = []
+parseSubFields :: String -> [(String,[String])] -> [(String,[String],[String])] -> [(String,String,String)] -> [Fragment] -> ServerObject -> [Field]
+parseSubFields [] _ _ _ _ _ = []
+parseSubFields str svrobjs soa vars fmts sobj = parseSubFieldsHelper str [] [] svrobjs soa True vars fmts sobj
+parseSubFieldsHelper :: String -> String -> String -> [(String,[String])] -> [(String,[String],[String])] -> Bool -> [(String,String,String)] -> [Fragment] -> ServerObject -> [Field]
+parseSubFieldsHelper [] [] [] _ _ _ _ _ _ = []
+parseSubFieldsHelper [] [] acc _ _ True _ _ _ = [Left $ createScalarType acc :: Field]
+parseSubFieldsHelper [] [] acc _ _ False _ _ _ = []
+parseSubFieldsHelper [] acc [] _ _ True _ _ _ = [Left $ createScalarType acc :: Field]
+parseSubFieldsHelper [] acc [] _ _ False _ _ _ = []
 -- There is not a case where both acc1 and acc2 are not empty, but I'll catch anyway
-parseSubFieldsHelper [] acc1 acc2 _ True _ = (Left $ createScalarType (acc2++acc1)):[]
-parseSubFieldsHelper [] acc1 acc2 _ False _ = []
-parseSubFieldsHelper (h:t) acc1 acc2 svrobjs inc vars
-    | h==':' = parseSubFieldsHelper (removeLeadingSpaces t) (acc2++acc1++[h]) [] svrobjs inc vars
-    | h==' '&&(length acc1)>0 = parseSubFieldsHelper t [] acc1 svrobjs inc vars
-    | h==' ' = parseSubFieldsHelper t acc1 acc2 svrobjs inc vars
-    | h==','&&(length acc1)>0&&(inc==True) = (Left $ createScalarType acc1 :: Field):parseSubFieldsHelper t [] [] svrobjs True vars
-    | h==','&&(length acc1)>0 = parseSubFieldsHelper t [] [] svrobjs True vars
-    | h==','&&(length acc2)>0&&(inc==True) = (Left $ createScalarType acc2 :: Field):parseSubFieldsHelper t [] [] svrobjs True vars
-    | h==','&&(length acc2)>0 = parseSubFieldsHelper t [] [] svrobjs True vars
-    | h=='('&&(length acc1)>0 = parseSubFieldsHelper selectTail (acc1++[h]++subselect) [] svrobjs inc vars
-    | h=='('&&(length acc2)>0 = parseSubFieldsHelper selectTail (acc2++[h]++subselect) [] svrobjs inc vars
-    | h=='{'&&(length acc1)>0&&(inc==True) = (Right $ (createNestedObject (acc1++[h]++level) svrobjs vars) :: Field):parseSubFieldsHelper levelTail [] [] svrobjs True vars
-    | h=='{'&&(length acc1)>0 = parseSubFieldsHelper levelTail [] [] svrobjs True vars
-    | h=='{'&&(length acc2)>0&&(inc==True) = (Right $ (createNestedObject (acc2++[h]++level) svrobjs vars) :: Field):parseSubFieldsHelper levelTail [] [] svrobjs True vars
-    | h=='{'&&(length acc2)>0 = parseSubFieldsHelper levelTail [] [] svrobjs True vars
-    | h=='@'&&(directive==True) = parseSubFieldsHelper directiveTail acc1 acc2 svrobjs True vars
-    | h=='@' = parseSubFieldsHelper directiveTail acc1 acc2 svrobjs False vars
-    | h=='}' = parseSubFieldsHelper t acc1 acc2 svrobjs inc vars
-    | (length acc2)>0&&inc==True = (Left $ createScalarType acc2 :: Field):parseSubFieldsHelper t (acc1++[h]) [] svrobjs True vars
-    | (length acc2)>0 = parseSubFieldsHelper t (acc1++[h]) [] svrobjs True vars
-    | otherwise = parseSubFieldsHelper t (acc1++[h]) [] svrobjs inc vars
+parseSubFieldsHelper [] acc1 acc2 _ _ True _ _ _ = (Left $ createScalarType (acc2++acc1)):[]
+parseSubFieldsHelper [] acc1 acc2 _ _ False _ _ _ = []
+parseSubFieldsHelper (h:t) acc1 acc2 svrobjs soa inc vars fmts sobj
+    | h==':' = parseSubFieldsHelper (removeLeadingSpaces t) (acc2++acc1++[h]) [] svrobjs soa inc vars fmts sobj
+    | h==' '&&(length acc1)>0 = parseSubFieldsHelper t [] acc1 svrobjs soa inc vars fmts sobj
+    | h==' ' = parseSubFieldsHelper t acc1 acc2 svrobjs soa inc vars fmts sobj
+    | h==','&&(length acc1)>0&&(inc==True) = (Left $ createScalarType acc1 :: Field):parseSubFieldsHelper t [] [] svrobjs soa True vars fmts sobj
+    | h==','&&(length acc1)>0 = parseSubFieldsHelper t [] [] svrobjs soa True vars fmts sobj
+    | h==','&&(length acc2)>0&&(inc==True) = (Left $ createScalarType acc2 :: Field):parseSubFieldsHelper t [] [] svrobjs soa True vars fmts sobj
+    | h==','&&(length acc2)>0 = parseSubFieldsHelper t [] [] svrobjs soa True vars fmts sobj
+    | h=='('&&(length acc1)>0 = parseSubFieldsHelper selectTail (acc1++[h]++subselect) [] svrobjs soa inc vars fmts sobj
+    | h=='('&&(length acc2)>0 = parseSubFieldsHelper selectTail (acc2++[h]++subselect) [] svrobjs soa inc vars fmts sobj
+    | h=='{'&&(length acc1)>0&&(inc==True) = (Right $ (Left $ (createNestedObject (acc1++[h]++level) svrobjs soa vars fmts) :: FieldObject) :: Field):parseSubFieldsHelper levelTail [] [] svrobjs soa True vars fmts sobj
+    | h=='{'&&(length acc1)>0 = parseSubFieldsHelper levelTail [] [] svrobjs soa True vars fmts sobj
+    | h=='{'&&(length acc2)>0&&(inc==True) = (Right $ (Left $ (createNestedObject (acc2++[h]++level) svrobjs soa vars fmts) :: FieldObject) :: Field):parseSubFieldsHelper levelTail [] [] svrobjs soa True vars fmts sobj
+    | h=='{'&&(length acc2)>0 = parseSubFieldsHelper levelTail [] [] svrobjs soa True vars fmts sobj
+    | h=='@'&&directive==True = parseSubFieldsHelper directiveTail acc1 acc2 svrobjs soa True vars fmts sobj
+    | h=='@' = parseSubFieldsHelper directiveTail acc1 acc2 svrobjs soa False vars fmts sobj
+    | h=='.'&&(length acc1)>0 = parseSubFieldsHelper t (acc1++[h]) [] svrobjs soa True vars fmts sobj
+    | h=='.'&&(length acc2)>0&&inc==True = if isInlineFragment then (Left $ createScalarType acc2 :: Field):(Right (Right $ (createInlinefragmentObject inlinefragmentBody inlinefragmentObj vars fmts svrobjs soa) :: FieldObject) :: Field):parseSubFieldsHelper inlinefragmentTail [] [] svrobjs soa True vars fmts sobj else parseSubFieldsHelper (fContents++fragmentTail) [] [] svrobjs soa inc vars fmts sobj
+    | h=='.'&&(length acc2)>0 = if isInlineFragment then (Right (Right $ (createInlinefragmentObject inlinefragmentBody inlinefragmentObj vars fmts svrobjs soa) :: FieldObject) :: Field):parseSubFieldsHelper inlinefragmentTail [] [] svrobjs soa True vars fmts sobj else parseSubFieldsHelper (fContents++fragmentTail) [] [] svrobjs soa inc vars fmts sobj
+    | h=='.'&&isInlineFragment==True = (Right (Right $ (createInlinefragmentObject inlinefragmentBody inlinefragmentObj vars fmts svrobjs soa) :: FieldObject) :: Field):parseSubFieldsHelper inlinefragmentTail [] [] svrobjs soa True vars fmts sobj
+    | h=='.' = parseSubFieldsHelper (fContents++fragmentTail) [] [] svrobjs soa inc vars fmts sobj
+    | h=='}' = parseSubFieldsHelper t acc1 acc2 svrobjs soa inc vars fmts sobj  -- this character is removed when I pull a level
+    | (length acc2)>0&&inc==True = (Left $ createScalarType acc2 :: Field):parseSubFieldsHelper t (acc1++[h]) [] svrobjs soa True vars fmts sobj
+    | (length acc2)>0 = parseSubFieldsHelper t (acc1++[h]) [] svrobjs soa True vars fmts sobj
+    | otherwise = parseSubFieldsHelper t (acc1++[h]) [] svrobjs soa inc vars fmts sobj
   where
     (level,levelTail) = splitLevel t "" 0
     (subselect,selectTail) = getSubSelection t
     (directive,directiveTail) = checkDirective (h:t) vars
+    (isInlineFragment,inlinefragmentObj,inlinefragmentBody,inlinefragmentTail) = checkInlinefragment (h:t)
+    (fragmentName,fragmentTail) = findFragment (h:t)
+    fContents = expandFragment fragmentName sobj fmts
+
+checkInlinefragment :: String -> (Bool,String,String,String)
+checkInlinefragment str = checkInlinefragmentHelper str [] False []
+checkInlinefragmentHelper :: String -> String -> Bool -> String -> (Bool,String,String,String)
+checkInlinefragmentHelper [] _ _ _ = (False,[],[],[])
+checkInlinefragmentHelper (h:t) acc sobj obj
+    | (length acc)<3&&h=='.' = checkInlinefragmentHelper t (acc++[h]) False []
+    | (length acc)<3 = throw ParseFragmentException
+    | (length acc)==3&&h/=' ' = (False,[],[],(acc++(h:t)))
+    | (length acc)==3 = checkInlinefragmentHelper t (acc++[h]) False []
+    | (length acc)==4&&h==' ' = checkInlinefragmentHelper t acc False []
+    | (length acc)==4&&h=='o' = checkInlinefragmentHelper t (acc++[h]) False []
+    | (length acc)==4 = throw ParseFragmentException
+    | (length acc)==5&&h=='n' = checkInlinefragmentHelper t (acc++[h]) False []
+    | (length acc)==5 = throw ParseFragmentException
+    | (length acc)==6&&h==' ' = checkInlinefragmentHelper t (acc++[h]) False []
+    | (length acc)==6 = throw ParseFragmentException
+    | (length acc)==7&&h==' ' = checkInlinefragmentHelper t acc False []
+    | (length acc)==7&&((fromEnum h)>=97||(fromEnum h)<=122) = checkInlinefragmentHelper t (acc++[h]) False [h]
+    | (length acc)==7 = throw ParseFragmentException
+    | (length acc)>7&&sobj==False&&(isValidIdentifierChar h) = checkInlinefragmentHelper t acc False (obj++[h])
+    | (length acc)>7&&sobj==False&&h==' ' = checkInlinefragmentHelper t acc True obj
+    | (length acc)>7&&h==' ' = checkInlinefragmentHelper t acc True obj
+    | (length acc)>7&&h/='{' = throw ParseFragmentException
+    | (length acc)>7 = (True,obj,contents,tail)
+    | otherwise = throw ParseFragmentException
+  where
+    (contents,tail) = splitSubject t [] 0 
+createInlinefragmentObject :: String -> String -> [(String,String,String)] -> [Fragment] -> [(String,[String])] -> [(String,[String],[String])] -> InlinefragmentObject
+createInlinefragmentObject bdy obj vars fmts svrobjs soa = (InlinefragmentObject (readServerObject obj svrobjs soa) ((parseSubFields bdy svrobjs soa vars fmts obj) :: SubFields))
+
+findFragment :: String -> (String,String)
+findFragment [] = throw ParseFragmentException
+findFragment str = findFragmentHelper str []
+findFragmentHelper :: String -> String -> (String,String)
+findFragmentHelper [] acc = (acc,[])
+findFragmentHelper (h:t) acc
+  | (length acc)<3&&h=='.' = findFragmentHelper t (acc++[h])
+  | (length acc)<3 = throw ParseFragmentException
+  | (length acc)==3&&(isValidFragmentNameChar h) = findFragmentHelper t (acc++[h])
+  | (length acc)==3 = throw ParseFragmentException
+  | (length acc)>3&&(isValidFragmentNameChar h) = findFragmentHelper t (acc++[h])
+  | (length acc)>3&&h==' ' = (acc,t)
+  | otherwise = throw ParseFragmentException
+    
+expandFragment :: String -> ServerObject -> [Fragment] -> String
+expandFragment _ _ [] = throw ParseFragmentException
+expandFragment fnm sobj (h:t) = if (targetObject h)==sobj&&fnm==("..."++(name h)) then (replacement h) else expandFragment fnm sobj t
+
 removeLeadingSpaces :: String -> String
 removeLeadingSpaces [] = []
 removeLeadingSpaces (h:t) = if h==' ' then removeLeadingSpaces t else (h:t)
@@ -354,7 +371,7 @@     | directive=="include"&&value=="false"=(False,tail)
     | directive=="skip"&&value=="true"=(False,tail)
     | directive=="skip"&&value=="false"=(True,tail)
-    | otherwise = E.throw InvalidScalarException
+    | otherwise = throw InvalidScalarException
   where
     directive = toLowercase dir
     value = if h=='$' then toLowercase $ getVariableValue vars (h:t) else toLowercase (h:t)
@@ -374,20 +391,17 @@     tail = getSuffix t ')'
 getPrefix :: String -> Char -> String
 getPrefix [] _ = []
-getPrefix str chr = getPrefixHelper str chr ""
-getPrefixHelper :: String -> Char -> String -> String
-getPrefixHelper [] _ _ = ""
-getPrefixHelper (h:t) trg acc = if h==trg then acc else getPrefixHelper t trg (acc++[h])
+getPrefix (h:t) chr = if (h==chr) then [] else h:getPrefix t chr
 getSuffix :: String -> Char -> String
 getSuffix [] _ = []
 getSuffix (h:t) chr = if h==chr then t else getSuffix t chr
 toLowercase :: String -> String
 toLowercase str = [toLower c | c <- str]
 getVariableValue :: [(String,String,String)] -> String -> String
-getVariableValue [] _ = E.throw InvalidVariableNameException
+getVariableValue [] _ = throw InvalidVariableNameException
 getVariableValue ((name,typ,val):t) var
     | (name==var)&&(typ=="Bool") = val
-    | (name==var) = E.throw MismatchedVariableTypeException
+    | (name==var) = throw MismatchedVariableTypeException
     | otherwise = getVariableValue t var
 -- pull level and leave out closing brace.
 extractLevel :: String -> String
@@ -414,19 +428,19 @@ removeSpaces :: String -> String
 removeSpaces str = [x | x <- str, x/=' ']
 createScalarType :: String -> ScalarType
-createScalarType [] = E.throw InvalidScalarException
+createScalarType [] = throw InvalidScalarException
 createScalarType str = ScalarType (parseAlias str :: Alias) (parseName str :: Name) (parseTransformation str :: Transformation) (parseArgument str :: Argument)
 parseTransformation :: String -> Transformation
 parseTransformation [] = Nothing :: Transformation
 parseTransformation str
     | (elem '(' str)&&(elem ':' str) = (Just $ removeSideSpaces $ foldr (\x y -> if x==':' then [] else x:y) "" $ foldl (\y x -> if x=='(' then [] else y++[x]) "" str) :: Transformation
-    | (elem '(' str) = E.throw SyntaxException
+    | (elem '(' str) = throw SyntaxException
     | otherwise = Nothing :: Transformation
 parseArgument :: String -> Argument
 parseArgument [] = Nothing :: Argument
 parseArgument str
     | (elem ')' str)&&(elem ':' str) = (Just $ removeSideSpaces $ foldr (\x y -> if x==')' then [] else x:y) "" $ foldl (\y x -> if x==':' then [] else y++[x]) "" str) :: Argument
-    | (elem ')' str) = E.throw SyntaxException
+    | (elem ')' str) = throw SyntaxException
     | otherwise = Nothing :: Argument
 removeSideSpaces :: String -> String
 removeSideSpaces str = foldl (\y x -> if (x==' '&&(length y)==0) then [] else y++[x]) "" $ foldr (\x y -> if (x==' '&&(length y)==0) then [] else x:y) "" str
src/Components/Parsers/ServerSchemaJsonParser.hs view
@@ -1,54 +1,87 @@ module Components.Parsers.ServerSchemaJsonParser (fetchArguments) where
 
-import qualified Control.Exception as E
-import Text.JSON
-import Model.ServerExceptions
+import Control.Exception (throw)
+import Text.JSON (
+    JSValue(JSObject),
+    JSObject,
+    Result(Ok,Error),
+    valFromObj,
+    decode
+  )
+import Model.ServerExceptions (
+    QueryException(
+      ImportSchemaServerNameException,
+      ImportSchemaException,
+      ImportSchemaChildrenException,
+      ImportSchemaPseudonymsException,
+      ImportSchemaServerNameException,
+      ImportSchemaScalarFieldsException,
+      ImportSchemaDatabaseTablesException,
+      ImportSchemaObjectFieldsException,
+      ImportSchemaDatabaseRelationshipsException
+    )
+  )
 
 
-fetchArguments :: FilePath -> IO ([(String,[String])],[(String,[(String,String)])],[(String,[String])],[(String,[String])],[(String,String,[String])])
+fetchArguments :: FilePath -> IO ([(String,[String])],[(String,[(String,String)])],[(String,[String])],[(String,String)],[(String,String,[String])],[(String,[String],[String])])
 fetchArguments fp = do 
     schema <- Prelude.readFile fp
-    let parsed = schema
-    return $ parseSchema parsed
-parseSchema :: 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 (Error str) = E.throw ImportSchemaException
+    return $ parseSchema schema
+parseSchema :: 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 (Error str) = throw ImportSchemaException
 checkJSValueListValue (Ok a) = a
-parseHelper :: [(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])])
-parseHelper svrobjs sss sos sdbn sor [] = (svrobjs,sss,sos,sdbn,sor)
-parseHelper svrobjs sss sos sdbn sor (obj:t) = parseHelper ((name,pseudonyms):svrobjs) ((name,scalars):sss) ((name,nestedobjects):sos) ((name,tables):sdbn) (sor++(processRelationships relationships)) t
+parseHelper :: JSObject JSValue -> ([(String,[String])],[(String,[(String,String)])],[(String,[String])],[(String,String)],[(String,String,[String])],[(String,[String],[String])])
+parseHelper json = (svrobjs,sss,sos,sdbn,sor,soa)
   where
-    name = getServerName (valFromObj "servername" obj :: Result String)
-    pseudonyms = getStringList (valFromObj "pseudonyms" obj :: Result [String]) 0
-    scalars = checkScalars (valFromObj "scalarfields" obj :: Result [JSValue])
-    nestedobjects = getStringList (valFromObj "objectfields" obj :: Result [String]) 1
-    tables = getStringList (valFromObj "databasetables" obj :: Result [String]) 2
-    relationships = getListStringList (valFromObj "databaserelationships" obj :: Result [[String]])
-getServerName :: Result String -> String
-getServerName (Error str) = E.throw ImportSchemaServerNameException
-getServerName (Ok name) = name
+    (svrobjs,sss,sos,sdbn,sor) = parsePrimitivesIterator [] [] [] [] [] $ getObjects (valFromObj "PrimitiveObjects" json :: Result [JSObject JSValue])
+    soa = parseParentsIterator [] $ getObjects (valFromObj "ParentalObjects" json :: Result [JSObject JSValue])
+parsePrimitivesIterator :: [(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])])
+parsePrimitivesIterator svrobjs sss sos sdbn sor [] = (svrobjs,sss,sos,sdbn,sor)
+parsePrimitivesIterator svrobjs sss sos sdbn sor (obj:t) = parsePrimitivesIterator ((name,pseudonyms):svrobjs) ((name,scalars):sss) ((name,nestedobjects):sos) ((name,table):sdbn) (sor++(processRelationships relationships)) t
+  where
+    name = getString (valFromObj "ServerName" obj :: Result String) 0
+    pseudonyms = getStringList (valFromObj "Pseudonyms" obj :: Result [String]) 0
+    scalars = checkScalars (valFromObj "ScalarFields" obj :: Result [JSValue])
+    nestedobjects = getStringList (valFromObj "ObjectFields" obj :: Result [String]) 1
+    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 [] = soa
+parseParentsIterator soa (obj:t) = 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]) 2
+getObjects :: Result [JSObject JSValue] -> [JSObject JSValue]
+getObjects (Error _) = throw ImportSchemaServerNameException
+getObjects (Ok objects) = objects
+getString :: Result String -> Int -> String
+getString (Ok str) _ = str
+getString (Error str) t
+  | t==0 = throw ImportSchemaServerNameException
+  | t==1 = throw ImportSchemaScalarFieldsException
+  | t==2 = throw ImportSchemaDatabaseTablesException
+  | otherwise = throw ImportSchemaException
 getStringList :: Result [String] -> Int -> [String]
 getStringList (Ok rlt) _ = rlt
 getStringList _ t
-    | t==0 = E.throw ImportSchemaPseudonymsException
-    | t==1 = E.throw ImportSchemaObjectFieldsException
-    | t==2 = E.throw ImportSchemaDatabaseTablesException
-    | otherwise = E.throw ImportSchemaException
+  | t==0 = throw ImportSchemaPseudonymsException
+  | t==1 = throw ImportSchemaObjectFieldsException
+  | t==2 = throw ImportSchemaChildrenException
+  | otherwise = throw ImportSchemaException
 getListStringList :: Result [[String]] -> [[String]]
-getListStringList (Error str) = E.throw ImportSchemaDatabaseRelationshipsException
+getListStringList (Error str) = throw ImportSchemaDatabaseRelationshipsException
 getListStringList (Ok rlt) = rlt
 checkScalars :: Result [JSValue] -> [(String,String)]
-checkScalars (Error str) = E.throw ImportSchemaScalarFieldsException
+checkScalars (Error str) = throw ImportSchemaScalarFieldsException
 checkScalars (Ok a) = getScalars a
 getScalars :: [JSValue] -> [(String,String)]
 getScalars [] = []
-getScalars ((JSObject obj):t) = (getString (valFromObj "name" obj :: Result String),getType (valFromObj "type" obj :: Result String)):(getScalars t)
-getString :: Result String -> String
-getString (Error str) = E.throw ImportSchemaScalarFieldsException
-getString (Ok a) = a
+getScalars ((JSObject obj):t) = (getString (valFromObj "Name" obj :: Result String) 1,getType (valFromObj "Type" obj :: Result String)):(getScalars t)
 getType :: Result String -> String
-getType (Error str) = E.throw ImportSchemaScalarFieldsException
+getType (Error str) = throw ImportSchemaScalarFieldsException
 getType (Ok a)
     | a=="Text" = a
     | a=="ByteString" = a
@@ -59,12 +92,12 @@     | a=="Day" = a
     | a=="TimeOfDay" = a
     | a=="UTCTime" = a
-    | otherwise = E.throw ImportSchemaScalarFieldsException
+    | otherwise = throw ImportSchemaScalarFieldsException
 processRelationships :: [[String]] -> [(String,String,[String])]
 processRelationships lst = foldr (\x y -> (getFirst x,getThird x, x):y) [] lst
 getFirst :: [String] -> String
 getFirst (h:t) = h
-getFirst _ = E.throw ImportSchemaException
+getFirst _ = throw ImportSchemaException
 getThird :: [String] -> String
 getThird (h1:h2:h3:t) = h3
-getThird _ = E.throw ImportSchemaException
+getThird _ = throw ImportSchemaException
src/Components/Parsers/VariablesParser.hs view
@@ -1,9 +1,18 @@ module Components.Parsers.VariablesParser where
 
-import Text.JSON
-import Data.Maybe
-import qualified Control.Exception as E
-import Model.ServerExceptions
+import Model.ServerExceptions (
+        QueryException(
+            MissingVariableValueException,
+            ReadVariablesException,
+            VariablesSyntaxException,
+            EmptyQueryException,
+            VariablesSyntaxException,
+            InvalidVariableTypeException
+        )
+    )
+import Control.Exception (throw)
+import Text.JSON (JSValue,JSObject,fromJSObject,Result(Ok,Error),encode,decode)
+import Data.Maybe (fromJust,Maybe(Nothing,Just))
 
 
 -- with a variables string and query string, we want the query variables, the type, and the value
@@ -12,10 +21,10 @@ -- with variable-values and variable-types, we want query variable-type-values
 filterToDesired :: [(String,String)] -> [(String,String,Maybe String)] -> [(String,String,String)]
 filterToDesired _ [] = []
-filterToDesired [] tvar = if (anyMaybeMissingValues tvar)==True then E.throw MissingVariableValueException else (getDefaultValues tvar)
+filterToDesired [] tvar = if (anyMaybeMissingValues tvar)==True then throw MissingVariableValueException else (getDefaultValues tvar)
 filterToDesired vvar tvars = [findVariableValue tvar vvar | tvar<-tvars]
 findVariableValue :: (String,String,Maybe String) -> [(String,String)] -> (String,String,String)
-findVariableValue (vname,vtype,vval) [] = if vval==Nothing then E.throw MissingVariableValueException else (vname,vtype,fromJust vval :: String)
+findVariableValue (vname,vtype,vval) [] = if vval==Nothing then throw MissingVariableValueException else (vname,vtype,fromJust vval :: String)
 findVariableValue (vname1,vtype,vval1) ((vname2,vval2):t) = if (vname1==vname2) then (vname1,vtype,vval2) else (findVariableValue (vname1,vtype,vval1) t)
 anyMaybeMissingValues :: [(String,String,Maybe String)] -> Bool
 anyMaybeMissingValues vars = foldr (\(nam,typ,val) y -> (val==Nothing)||y) False vars
@@ -26,7 +35,7 @@ parseVariableValuePairs [] = []
 parseVariableValuePairs vars = castValues $ fromJSObject $ checkVariables (decode vars :: Result (JSObject JSValue))
 checkVariables :: Result (JSObject JSValue) -> JSObject JSValue
-checkVariables (Error str) = E.throw ReadVariablesException
+checkVariables (Error str) = throw ReadVariablesException
 checkVariables (Ok vars) = vars
 castValues :: [(String,JSValue)] -> [(String,String)]
 castValues vars = [("$"++(removeQuotations name),encode val) | (name,val)<-vars]
@@ -34,31 +43,31 @@ removeQuotations (h1:h2:t) = if (h1=='\\')&&(h2=='"') then (removeQuotations t) else h1:(removeQuotations (h2:t))
 removeQuotations str = str
 getVariableTypePairs :: String -> [(String,String,Maybe String)]
-getVariableTypePairs [] = E.throw EmptyQueryException
+getVariableTypePairs [] = throw EmptyQueryException
 getVariableTypePairs qry
     | (elem '(' epilogue)&&(elem ')' epilogue) = separateVariables False "" False "" "" $ removeLeadingSpaces $ foldl (\y x -> if x=='(' then [] else y++[x]) [] $ foldr (\x y -> if x==')' then [] else x:y) [] epilogue
-    | (elem '(' epilogue) = E.throw VariablesSyntaxException
-    | (elem ')' epilogue) = E.throw VariablesSyntaxException
+    | (elem '(' epilogue) = throw VariablesSyntaxException
+    | (elem ')' epilogue) = throw VariablesSyntaxException
     | otherwise = []
   where
     epilogue = getQueryEpilogue qry
 getQueryEpilogue :: String -> String
-getQueryEpilogue [] = E.throw EmptyQueryException
+getQueryEpilogue [] = throw EmptyQueryException
 getQueryEpilogue (h:t) = if (h=='{') then [] else h:(getQueryEpilogue t)
 removeLeadingSpaces :: String -> String
 removeLeadingSpaces (h:t) = if (h==' ') then removeLeadingSpaces t else (h:t)
 separateVariables :: Bool -> String -> Bool -> String -> String -> String -> [(String,String,Maybe String)]
 separateVariables _ [] _ _ _ [] = []  -- no variables
-separateVariables _ var _ [] _ [] = E.throw VariablesSyntaxException  -- variable without type
-separateVariables _ var _ typ [] [] = if (isValidBaseType typ) then (var,typ,Nothing):[] else E.throw InvalidVariableTypeException  -- variable without default value
-separateVariables _ var _ typ dval [] = if (isValidBaseType typ) then (var,typ,Just $ removeTailSpaces dval):[] else E.throw InvalidVariableTypeException  -- variable with default value
+separateVariables _ var _ [] _ [] = throw VariablesSyntaxException  -- variable without type
+separateVariables _ var _ typ [] [] = if (isValidBaseType typ) then (var,typ,Nothing):[] else throw InvalidVariableTypeException  -- variable without default value
+separateVariables _ var _ typ dval [] = if (isValidBaseType typ) then (var,typ,Just $ removeTailSpaces dval):[] else throw InvalidVariableTypeException  -- variable with default value
 separateVariables var acc1 typ acc2 acc3 (h:t)
     | (var==False)&&(h/=':') = separateVariables var (acc1++[h]) typ acc2 acc3 t
     | (var==False) = separateVariables True (removeTailSpaces acc1) False [] [] (removeLeadingSpaces t)
-    | (typ==False)&&(h==',') = if (isValidBaseType finalizedType)==True then (acc1,finalizedType,Nothing):(separateVariables False [] False [] [] (removeLeadingSpaces t)) else E.throw InvalidVariableTypeException
+    | (typ==False)&&(h==',') = if (isValidBaseType finalizedType)==True then (acc1,finalizedType,Nothing):(separateVariables False [] False [] [] (removeLeadingSpaces t)) else throw InvalidVariableTypeException
     | (typ==False)&&(h/='=') = separateVariables var acc1 typ (acc2++[h]) [] t
     | (typ==False)&&(isValidBaseType finalizedType) = separateVariables var acc1 True finalizedType [] (removeLeadingSpaces t)
-    | (typ==False) = E.throw InvalidVariableTypeException
+    | (typ==False) = throw InvalidVariableTypeException
     | (h/=',') = separateVariables var acc1 typ acc2 (acc3++[h]) t
     | otherwise = (acc1,acc2,if (length finalizedValue)==0 then Nothing else (Just $ finalizedValue)):(separateVariables False [] False [] [] $ removeLeadingSpaces t)
   where
src/Components/QueryComposers/SQLQueryComposer.hs view
@@ -1,70 +1,74 @@ module Components.QueryComposers.SQLQueryComposer (makeSqlQueries) where
 
-import Data.Either
-import qualified Data.Map.Strict as M
-import qualified Control.Exception as E
-import Model.ServerObjectTypes
-import Model.ServerExceptions
-import Components.ObjectHandlers.ObjectsHandler
+import Model.ServerObjectTypes (RootObject,NestedObject,SubFields)
+import Model.ServerExceptions (QueryException(CreatingSqlQueryObjectsException,CreatingSqlQueryObjectFieldsException,InvalidObjectException,InvalidScalarException,RelationshipConfigurationException))
+import Components.ObjectHandlers.ObjectsHandler (translateServerObjectToDBName,getSubSelectionArgument,getSubSelectionField,withSubSelection,getDBObjectRelationships,getServerObject,getInlinefragmentObject,getInlinefragmentFields,isServerObjectTable,getSubFields,getScalarName,isServerObjectTable)
+import Data.Either (fromLeft,fromRight,isRight,isLeft)
+import Data.Map.Strict (fromList,Map,(!),insertWith)
+import Control.Exception (throw)
 
 
-makeSqlQueries :: [RootObject] -> [(String,[String])] -> [(String,String,[String])] -> [[String]]
-makeSqlQueries [] _ _ = []
-makeSqlQueries (h:t) sodn sor = (makeSqlQuerySet h sodn sor):(makeSqlQueries t sodn sor)
-makeSqlQuerySet :: RootObject -> [(String,[String])] -> [(String,String,[String])] -> [String]
-makeSqlQuerySet obj sodn sor = if (length dbNames)==1 then (addSqlQueryFields (getSubFields obj) (M.fromList [((head dbNames),1)]) ("select "++(head dbNames)++(show 1)++".id,") (" from"++(makeSqlTablePhrase obj (head dbNames) 1)) (" order by "++(head dbNames)++(show 1)++".id asc") (((head dbNames)++(show 1)):[]) [] [(head dbNames)] sodn sor) else (foldr (\x y -> x++y) [] [(addSqlQueryFields (getSubFields obj) (M.fromList [(x,1)]) ("select "++x++(show 1)++".id,") (" from"++(makeSqlTablePhrase obj x 1)) (" order by "++x++(show 1)++".id asc") ((x++(show 1)):[]) [] [x] sodn sor) | x<-dbNames])
+makeSqlQueries :: [RootObject] -> [(String,String)] -> [(String,String,[String])] -> [(String,[String],[String])] -> ([[[String]]],[[String]])
+makeSqlQueries [] _ _ _ = ([],[])
+makeSqlQueries rojs sodn sor soa = unzip $ map unzip $ map (makeSqlQuerySet sodn sor soa) rojs
+makeSqlQuerySet :: [(String,String)] -> [(String,String,[String])] -> [(String,[String],[String])] -> RootObject -> [([String],String)]
+makeSqlQuerySet sodn sor soa obj = if (length dbNames)==1 then (addSqlQueryFields (getSubFields obj) (fromList [(firstTable,1)]) ("select "++firstTable++(show 1)++".id,") (" from"++(makeSqlTablePhrase obj firstTable 1)) (" order by "++firstTable++(show 1)++".id asc") (((firstTable,1):[])) [] sodn sor soa (firstTable:[])) else (foldr (\x y -> x++y) [] [(addSqlQueryFields (getSubFields obj) (fromList [(x,1)]) ("select "++x++(show 1)++".id,") (" from"++(makeSqlTablePhrase obj x 1)) (" order by "++x++(show 1)++".id asc") ((x,1):[]) [] sodn sor soa (x:[])) | x<-dbNames])
                            where
-                             dbNames = translateServerObjectToDBName (getServerObject obj) sodn
+                             dbNames = translateServerObjectToDBName (getServerObject obj) sodn soa
+                             firstTable = head dbNames
 -- making table phrase when there is only one sql table
 makeSqlTablePhrase :: NestedObject -> String -> Int -> String
 makeSqlTablePhrase obj name number = if (withSubSelection obj)==True then " (select * from "++name++" where "++(getSubSelectionField obj)++"="++(getSubSelectionArgument obj)++") as "++name++(show number) else " "++name++" as "++name++(show number)
-addSqlQueryFields :: SubFields -> M.Map String Int -> String -> String -> String -> [String] -> [SubFields] -> [String] -> [(String,[String])] -> [(String,String,[String])] -> [String]
-addSqlQueryFields [] counts select from order [] [] ltable _ _ = [(removeLastChar select)++from++order++";"]
-addSqlQueryFields [] counts select from order [] (h:t) ltable _ _ = E.throw CreatingSqlQueryObjectFieldsException
-addSqlQueryFields [] counts select from order (h:t) [] ltable _ _ = [(removeLastChar select)++from++order++";"]
-addSqlQueryFields [] counts select from order (a:b) (h:t) ltable sodn sor = addSqlQueryFields h counts select from order b t ltable sodn sor
-addSqlQueryFields (h:t) counts select from order [] [] ltable _ _ = E.throw CreatingSqlQueryObjectsException
-addSqlQueryFields (h:t) counts select from order [] (a:b) ltable _ _ = E.throw CreatingSqlQueryObjectsException
-addSqlQueryFields (h:t) counts select from order names fields ltable sodn sor
-    | (isLeft h)==True = addSqlQueryFields t counts (select++(head names)++"."++(getScalarName $ fromLeft (E.throw InvalidScalarException) h)++",") from order names fields ltable sodn sor
+addSqlQueryFields :: SubFields -> Map String Int -> String -> String -> String -> [(String,Int)] -> [SubFields] -> [(String,String)] -> [(String,String,[String])] -> [(String,[String],[String])] -> [String] -> [([String],String)]
+addSqlQueryFields [] counts select from order [] [] _ _ _ tbls = [(tbls,(removeLastChar select)++from++order++";")]
+addSqlQueryFields [] counts select from order [] _ _ _ _ _ = throw CreatingSqlQueryObjectFieldsException
+addSqlQueryFields [] counts select from order _ [] _ _ _ tbls = [(tbls,(removeLastChar select)++from++order++";")]
+addSqlQueryFields [] counts select from order (_:b) (h:t) sodn sor soa tbls = addSqlQueryFields h counts select from order b t sodn sor soa tbls
+addSqlQueryFields (h:t) counts select from order [] _ _ _ _ _ = throw CreatingSqlQueryObjectsException  -- fields without objects
+addSqlQueryFields (h:t) counts select from order ((ltable,ltableNo):names) fields sodn sor soa tbls
+    | (isLeft h)==True = addSqlQueryFields t counts (select++(ltable++(show ltableNo))++"."++(getScalarName $ fromLeft (throw InvalidScalarException) h)++",") from order ((ltable,ltableNo):names) fields sodn sor soa tbls
     -- since only difference is table name, I should remove repeated computations by changing only name...
-    | tablesCount>1 = foldr (\x y -> x++y) [] [(addSqlQueryFields (getSubFields nobj) (calcNewCounts (head ltable) x) (select++x++(show $ (M.!) (calcNewCounts (head ltable) x) x)++".id,") (from++(makeTransitions (calcNewCounts (head ltable) x) (getDBObjectRelationships (head ltable) x sor) nobj)) (order++","++x++(show $ (M.!) (calcNewCounts (head ltable) x) x)++".id asc") ((x++(show $ (M.!) (calcNewCounts (head ltable) x) x)):names) (t:fields) [x] sodn sor) | x<-tables]
-    | otherwise = addSqlQueryFields (getSubFields nobj) (calcNewCounts (head ltable) $ head tables) (select++(head tables)++(show $ (M.!) (calcNewCounts (head ltable) $ head tables) (head tables))++".id,") (from++(makeTransitions (calcNewCounts (head ltable) $ head tables) (getDBObjectRelationships (head ltable) (head tables) sor) nobj)) (order++","++(head tables)++(show $ (M.!) (calcNewCounts (head ltable) $ head tables) (head tables))++".id asc") (((head tables)++(show ((calcNewCounts (head ltable) $ head tables) M.! (head tables)))):names) (t:fields) [(head tables)] sodn sor
+    | (isLeft fobj)&&(length tables)>1 = foldr (\x y -> x++y) [] [(addSqlQueryFields (getSubFields nobj) (calcNewCounts ltable x counts sor) (select++x++(show $ (!) (calcNewCounts ltable x counts sor) x)++".id,") (from++(makeTransitions (calcNewCounts ltable x counts sor) (getDBObjectRelationships ltable x sor) nobj)) (order++","++x++(show $ (!) (calcNewCounts ltable x counts sor) x)++".id asc") ((x,((calcNewCounts ltable x counts sor) ! x)):(ltable,ltableNo):names) (t:fields) sodn sor) soa (x:tbls) | x<-tables]
+    | (isLeft fobj)&&(length tables)>0 = addSqlQueryFields (getSubFields nobj) firstTableNewCounts (select++firstSubfieldTable++(show $ (!) firstTableNewCounts firstSubfieldTable)++".id,") (from++(makeTransitions firstTableNewCounts (getDBObjectRelationships ltable firstSubfieldTable sor) nobj)) (order++","++firstSubfieldTable++(show $ (!) firstTableNewCounts firstSubfieldTable)++".id asc") ((firstSubfieldTable,firstTableNewCounts ! firstSubfieldTable):(ltable,ltableNo):names) (t:fields) sodn sor soa (firstSubfieldTable:tbls)
+    | (isRight fobj)&&(isServerObjectTable ltable (getInlinefragmentObject ifobj) sodn soa) = addSqlQueryFields ((getInlinefragmentFields ifobj)++t) counts select from order ((ltable,ltableNo):names) fields sodn sor soa tbls
+    | otherwise = addSqlQueryFields t counts select from order ((ltable,ltableNo):names) fields sodn sor soa tbls
   where
-    calcNewCounts :: String -> String -> M.Map String Int
-    calcNewCounts from to = foldr (\x y -> M.insertWith (+) x 1 y) counts (getNewTables $ getDBObjectRelationships from to sor)
-    nobj = fromRight (E.throw InvalidObjectException) h
-    sobj = getServerObject nobj
-    tablesCount = length tables
-    tables = translateServerObjectToDBName sobj sodn
+    fobj = fromRight (throw InvalidObjectException) h
+    nobj = fromLeft (throw InvalidObjectException) fobj
+    ifobj = fromRight (throw InvalidObjectException) fobj    
+    tables = translateServerObjectToDBName (getServerObject nobj) sodn soa
+    firstSubfieldTable = head tables
+    firstTableNewCounts = calcNewCounts ltable firstSubfieldTable counts sor
+calcNewCounts :: String -> String -> Map String Int -> [(String,String,[String])] -> Map String Int
+calcNewCounts from to pcnt sor = foldr (\x y -> insertWith (+) x 1 y) pcnt (getNewTables $ getDBObjectRelationships from to sor)
 removeLastChar :: String -> String
 removeLastChar [] = []
 removeLastChar str = init str
 -- get the tables where we need to increment the tables counter
 getNewTables :: [String] -> [String]
-getNewTables lnk = (getNewTablesHelper (tail $ tail lnk) 0)
+getNewTables lnk = getNewTablesHelper (tail $ tail lnk) 0
 getNewTablesHelper :: [String] -> Int -> [String]
 getNewTablesHelper [] _ = []
 getNewTablesHelper (h:t) idx
     | (idx==0) = h:getNewTablesHelper (tail t) 3
     | ((mod idx 3)==0) = h:getNewTablesHelper t (idx+1)
     | otherwise = getNewTablesHelper t (idx+1)
-makeTransitions :: M.Map String Int -> [String] -> NestedObject -> String
-makeTransitions counts (h1:h2:h3:h4:h5:h6:h7:t) nobj = " inner join "++h5++" as "++h5++(show $ (M.!) counts h5)++" on "++(makeEqColumns (h1++(show $ (M.!) counts h1)) h2 (h5++(show $ (M.!) counts h5)) h6)++(completeTransition counts (h3:h4:h5:h6:h7:t) nobj)
-makeTransitions counts (h1:h2:h3:h4:t) nobj = " inner join "++(if (withSubSelection nobj)==True then ("(select * from "++h3++" where "++(getSubSelectionField nobj)++"="++(getSubSelectionArgument nobj)++")") else h3)++" as "++h3++(show $ (M.!) counts h3)++" on "++(makeEqColumns (h1++(show $ (M.!) counts h1)) h2 (h3++(show $ (M.!) counts h3)) h4)
-makeTransitions _ _ _ = E.throw RelationshipConfigurationException
-completeTransition :: M.Map String Int -> [String] -> NestedObject -> String
-completeTransition counts (h1:h2:h3:h4:h5:[]) nobj = " inner join "++(if (withSubSelection nobj)==True then ("(select * from "++h1++" where "++(getSubSelectionField nobj)++"="++(getSubSelectionArgument nobj)++")") else h1)++" as "++h1++(show $ (M.!) counts h1)++" on "++(makeEqColumns (h3++(show $ (M.!) counts h3)) h5 (h1++(show $ (M.!) counts h1)) h2)
-completeTransition counts (h1:h2:h3:h4:h5:h6:h7:h8:t) nobj = " inner join "++h6++" as "++h6++(show $ (M.!) counts h6)++" on "++(makeEqColumns (h3++(show $ (M.!) counts h3)) h5 (h6++(show $ (M.!) counts h6)) h7)++(completeTransition counts (h1:h2:h6:h7:h8:t) nobj)
-completeTransition counts _ _ = E.throw RelationshipConfigurationException
+makeTransitions :: Map String Int -> [String] -> NestedObject -> String
+makeTransitions counts (h1:h2:h3:h4:h5:h6:h7:t) nobj = " inner join "++h5++" as "++h5++(show $ (!) counts h5)++" on "++(makeEqColumns (h1++(show $ (!) counts h1)) h2 (h5++(show $ (!) counts h5)) h6)++(completeTransition counts (h3:h4:h5:h6:h7:t) nobj)
+makeTransitions counts (h1:h2:h3:h4:t) nobj = " inner join "++(if (withSubSelection nobj)==True then ("(select * from "++h3++" where "++(getSubSelectionField nobj)++"="++(getSubSelectionArgument nobj)++")") else h3)++" as "++h3++(show $ (!) counts h3)++" on "++(makeEqColumns (h1++(show $ (!) counts h1)) h2 (h3++(show $ (!) counts h3)) h4)
+makeTransitions _ _ _ = throw RelationshipConfigurationException
+completeTransition :: Map String Int -> [String] -> NestedObject -> String
+completeTransition counts (h1:h2:h3:h4:h5:[]) nobj = " inner join "++(if (withSubSelection nobj)==True then ("(select * from "++h1++" where "++(getSubSelectionField nobj)++"="++(getSubSelectionArgument nobj)++")") else h1)++" as "++h1++(show $ (!) counts h1)++" on "++(makeEqColumns (h3++(show $ (!) counts h3)) h5 (h1++(show $ (!) counts h1)) h2)
+completeTransition counts (h1:h2:h3:h4:h5:h6:h7:h8:t) nobj = " inner join "++h6++" as "++h6++(show $ (!) counts h6)++" on "++(makeEqColumns (h3++(show $ (!) counts h3)) h5 (h6++(show $ (!) counts h6)) h7)++(completeTransition counts (h1:h2:h6:h7:h8:t) nobj)
+completeTransition counts _ _ = throw RelationshipConfigurationException
 makeEqColumns :: String -> String -> String -> String -> String
 makeEqColumns tb1 col1 tb2 col2 = if ((elem ' ' col1)==False&&(elem ' ' col2)==False) then (tb1++"."++col1++"="++tb2++"."++col2) else makeEqColumnsHelper "" tb1 col1 tb2 col2
 makeEqColumnsHelper :: String -> String -> String -> String -> String -> String
 makeEqColumnsHelper rlt tb1 col1 tb2 col2
     | (elem ' ' col1)&&(elem ' ' col2)&&((length rlt)>0) = makeEqColumnsHelper (rlt++" and "++tb1++"."++fst++"="++tb2++"."++snd) tb1 rmd1 tb2 rmd2
     | (elem ' ' col1)&&(elem ' ' col2) = makeEqColumnsHelper (tb1++"."++fst++"="++tb2++"."++snd) tb1 rmd1 tb2 rmd2
-    | (elem ' ' col1) = E.throw RelationshipConfigurationException
-    | (elem ' ' col2) = E.throw RelationshipConfigurationException
+    | (elem ' ' col1) = throw RelationshipConfigurationException
+    | (elem ' ' col2) = throw RelationshipConfigurationException
     | ((length rlt)>0) = rlt++" and "++(tb1++"."++col1++"="++tb2++"."++col2)
     | otherwise = (tb1++"."++col1++"="++tb2++"."++col2)
   where
src/GraphQL.hs view
@@ -8,7 +8,7 @@ <https://graphql.github.io/ Here> is a link to the official documents. You can learn and get a feel of how can you implement this package which is a GraphQL-to-SQL translator with Persistent package return value processing to make a GraphQL format return object string.
 
 This module is made to enable interpreting your GraphQL queries. The expected query type is a single string to comprise all your GraphQL queries and fragments. Expected variable type is a single string to your variable-to-value definitions.
-
+`
 When errors are encountered, this module is simply going to throw an uncaught Exception. The Exception name is some hint to where was the error encountered. More information is provided in the below function description.
 
 Not all GraphQL features are currently supported. For a list to updates and current state, you should check the GitHub updates and example <https://github.com/jasonsychau/graphql-w-persistent page>.
@@ -16,385 +16,353 @@ -}
 module GraphQL (
     -- * Functions
-    -- | These are available methods to give access to the package interpretation, validation, and formatting features.
+    -- | Here is two methods to the package interpretation, validation, and formatting features.
     -- | NOTE: It is is assumed that all nested objects are corresponding to a database table with a primary key that's named "id".
     module GraphQL,
-    -- * Server data types
-    -- | These are server data types that are return from processQueryString. You do not need to know these to know how is this package used, but you'll get some insight to what is used to store and organize your GraphQL data.
-    module Model.ServerObjectTypes,
     -- * Server exceptions
     -- | These are server exceptions to make error handling.
     module Model.ServerExceptions
     ) where
 
 import Data.Text (Text)
-import Control.Monad.IO.Class as IO
-import qualified Components.Parsers.QueryParser as QP
-import qualified Components.Parsers.ServerSchemaJsonParser as JP
-import qualified Components.Parsers.VariablesParser as VP
-import qualified Components.DataProcessors.PersistentDataProcessor as DP
-import Model.ServerObjectTypes
+import Control.Monad.IO.Class (liftIO,MonadIO())
+import Control.Exception (throw)
+import Components.Parsers.QueryParser (validateQuery,parseStringToObjects,processString)
+import Components.ObjectHandlers.ServerObjectValidator (checkObjectsAttributes,replaceObjectsVariables)
+import Components.QueryComposers.SQLQueryComposer (makeSqlQueries)
+import Components.Parsers.ServerSchemaJsonParser (fetchArguments)
+import Components.ObjectHandlers.ServerObjectTrimmer (mergeDuplicatedRootObjects)
+import Components.Parsers.VariablesParser (parseVariables)
+import Components.DataProcessors.ListDataProcessor (processReturnedValues)
 import Model.ServerExceptions
-import GraphQLHelper
-
-
-{- | 
-   This is the simplest function to call to get queries from a GraphQL query. If you prefer to define schema in a json file, you may skip to the below processQueryStringWithJson function.
-
-   __Instructions to give server schema as arguments:__
-
-   (1) make a list to all server objects in the heirarchy in separate tuples with a list to all pseudonyms (that's including the ones that are referred in relationships as nested objects)
-   (2) make a list to all above mentioned server objects in separate tuples with a list to all valid scalar subfields as you read them from your database in a tuple with the variable type (valid types are Text, ByteString, Int, Double, Rational, Bool, Day, TimeOfDay, or UTCTime)
-   (3) make a list to all above mentioned server objects in separate tuples with a list to all valid nested relationship object subfields as you want them to be named (also include these in the first list)
-   (4) make a list to all above mentioned server objects in separate tuples with a list to all reference database table name(s) as you read them
-   (5) make a list to database table names in separate tuples with another database table name and a list to the SQL database tables that are between the two first tables; the list order is...
-   identity table name (the first String in this tuple), all identity leaving-field names (with a space to separate fields), referring table name (the table that's corresponding to the second String in this tuple), referring table entering-field name(s), and (if present) 
-   three String sequences that is intermediary-table name, intermediary-table entering-column name(s), and intermediary-table leaving-column name(s). The intermediary tables are ordered from closest to indentity table to closest to referencing table.
-
-   __To implement server type heirarchy:__
-   
-   * add new tuple to first schema argument,
-   * add new tuple to second schema argument (where list is the intersection fields on all children),
-   * add new tuple to third schema argument (where list is the intersection fields on all children),
-   * and add new tuple to fourth schema argument (where list is all children database tables).
-  
-   You should not need more cases within fifth schema argument, but you may find a child database table and third schema argument list elements pair that is not included.
-   
-   You then will need to include this, or error is thrown.
-
-   
-   Here is an example of the GraphQL schema arguments that are expected from the last five arguments. We'll use the GitHub <https://github.com/jasonsychau/graphql-w-persistent example> database schema 
-   to illustrate the expected arguments.
-
-
-   * The first schema argument (second argument) is a mapping to names to which a server object is possibly referred in any GraphQL query:
-
-   @
-       [("Person",["Person","person","owner"]),("Family",["Family","family"]),("Genus",["Genus","genus"]),("Species",["Species","species"]),("Breed",["Breed","breed"]),("Pet",["Pet","pet"]),("Taxonomy",["Taxonomy","taxonomy"])]
-   @
-
-   * The second schema argument is a mapping to valid scalar subfields and type from every server object that is listed in the first schema argument:
-
-   @
-       [("Person",[("id","Int"),("name","Text"),("gender","Int")]),("Family",[("id","Int"),("name","Text")]),("Genus",[("name","Text")]),("Species",[("id","Int"),("name","Text")]),("Breed",[("id","Int"),("name","Text")]),("Pet",[("id","Int"),("name","Text"),("gender","Int")]),("Taxonomy",[("name","Text")])]
-   @
-
-   NOTE: You should give only the intersection subfields set to parent server objects with all the children server objects.
-
-   NOTE: Valid scalar types are Text, ByteString, Int, Double, Rational, Bool, Day, TimeOfDay, or UTCTime.
-  
-   * The third schema argument is a mapping to valid nested object (or entity) subfields from every server object that is listed in the first schema argument:
-
-   @
-       [("Person",["pet"]),("Family",["genus","species","breed","pet"]),("Genus",["family","species","breed","pet"]),("Species",["family","genus","breed","pet"]),("Breed",["family","genus","species","pet"]),("Pet",["owner","breed","species","genus","family"]),("Taxonomy",["pet"])]
-   @
-
-   NOTE: You should give only the intersection subfields set to parent server objects with all the children server objects.
-
-   NOTE: You should also put the list names in the lists in the first argument to map the name to ServerObject.
-
-   * The fourth schema argument is a mapping to exact database names (it is maybe helpful to first have the database schema and copy names to this list mapping) for every listed server object in the first schema argument:
-
-   @
-       [("Person",["person"]),("Family",["family"]),("Genus",["genus"]),("Species",["species"]),("Breed",["breed"]),("Pet",["pet"]),("Taxonomy",["family","genus","species","breed"])]
-   @
-
-   NOTE: This is where can you introduce type heirarchies and generalizations. The above Taxonomy server object is an example. You can see that it is an encompassing term for all the biological classifications in our database schema. 
-
-   * The fifth schema argument is a mapping to exact database table names and fields names to link the from-object to the to-object.
-
-   Within every tuple,
-
-   the first String is the identity database table name (with type heirarchies, you make a separate tuple on every referenced database table if the to-from pair is not already mentioned as explicit pairing).
-
-   The second String is the referencing database name.
-
-   The third tuple value is a list that is showing the link between our identity table and referring table. The order is first identity database table name, second identity database leaving field name(s) (that are separated with a space), 
-   third referencing database table name, fourth referencing database table arrival field name(s), and the remainder (if identity table and referencing table are not directly linked) is a triplet of Strings that 
-   are ordered from nearest to identity table to closer to referencing table. The triplets are intermediate database table name, intermediate database arrival field(s), and intermediate database exiting 
-   field(s). Here is an illustration:
-
-   @
-       -- Person
-       [("person","pet",["person","id","pet","id","pet_ownership","owner_id","animal_id"]),
-       ("person","breed",["person","id","breed","id","pet_ownership","owner_id","animal_id","pet","id","id","pet_type","pet_id","breed_id"]),
-       ("person","species",["person","id","species","id","pet_ownership","owner_id","animal_id","pet","id","id","pet_type","pet_id","breed_id","breed","id","species_id"]),
-       ("person","genus",["person","id","genus","id","pet_ownership","owner_id","animal_id","pet","id","id","pet_type","pet_id","breed_id","breed","id","species_id","species","id","genus_id"]),
-       ("person","family",["person","id","family","id","pet_ownership","owner_id","animal_id","pet","id","id","pet_type","pet_id","breed_id","breed","id","species_id","species","id","genus_id","genus","id","family_id"]),
-       -- Family
-       ("family","pet",["family","id","pet","id","genus","family_id","id","species","genus_id","id","breed","species_id","id","pet_type","breed_id","pet_id"]),
-       ("family","genus",["family","id","genus","family_id"]),
-       ("family","species",["family","id","species","genus_id","genus","family_id","id"]),
-       ("family","breed",["family","id","breed","species_id","genus","family_id","id","species","genus_id","id"]),
-       -- Genus
-       ("genus","pet",["genus","id","pet","id","species","genus_id","id","breed","species_id","id","pet_type","breed_id","pet_id"]),
-       ("genus","family",["genus","family_id","family","id"]),
-       ("genus","species",["genus","id","species","genus_id"]),
-       ("genus","breed",["genus","id","breed","species_id","species","genus_id","id"]),
-       -- Species
-       ("species","pet",["species","id","pet","id","breed","species_id","id","pet_type","breed_id","pet_id"]),
-       ("species","breed",["species","id","breed","species_id"]),
-       ("species","genus",["species","genus_id","genus","id"]),
-       ("species","family",["species","id","family","genus_id","genus","species_id","id"]),
-       -- Breed
-       ("breed","pet",["breed","id","pet","id","pet_type","breed_id","pet_id"]),
-       ("breed","species",["breed","species_id","species","id"]),
-       ("breed","genus",["breed","species_id","genus","id","species","id","genus_id"]),
-       ("breed","family",["breed","species_id","family","id","species","id","genus_id","genus","id","family_id"]),
-       -- Pet
-       ("pet","person",["pet","id","person","id","pet_ownership","animal_id","owner_id"]),
-       ("pet","breed",["pet","id","breed","id","pet_type","pet_id","breed_id"]),
-       ("pet","species",["pet","id","species","id","pet_type","pet_id","breed_id","breed","id","species_id"]),
-       ("pet","genus",["pet","id","genus","id","pet_type","pet_id","breed_id","breed","id","genus_id"]),
-       ("pet","family",["pet","id","family","id","pet_type","pet_id","breed_id","breed","id","genus_id","genus","id","family_id"])]
-   @
-
-   When an error is encountered, an uncaught exception is thrown. Exceptions thrown by this function are:
-
-   * SyntaxException (when there is a problem with the given GraphQL query syntax)
-   * ParseFragmentException (when there is a problem with a Fragment syntax)
-   * EmptyQueryException (when the query is left blank)
-   * InvalidObjectException (when there is problem in nested object syntax, an object is not recognized, or server data is misinterpreted)
-   * InvalidObjectSubFieldException (when a subfield is requested from nested object that is not having ownership of the subfield)
-   * InvalidScalarException (when there is syntax error in listing scalar fields, or server data is misinterpreted)
-   * NullArgumentException (when a transformation is set but no argument is given though we do not yet support transformations) 
-   * CreatingSqlQueryObjectFieldsException (when there are too many nested object subfields than nested objects to hold them or when there is a problem with the aligning of server object relationship argument - that's the fifth schema argument)
-   * RelationshipConfigurationException (when the relationship schema fifth arugment is incorrect number of String values, when an unrecognized pairing is found, or when two table field cardinalities are not same)
-   * FailedObjectEqualityException (when we could not match identical queries)
-   * DuplicateRootObjectsException (when there is an overlapping query)
-   
-   As a final note, we turn our attention to what is posted on the official GraphQL docs:
-  
-   @"In contrast, GraphQL only returns the data that's explicitly requested, so new capabilities can be added via new types and new fields on those types without creating a breaking change. This has lead to a common practice of always avoiding breaking changes and serving a versionless API."@ - <https://graphql.github.io/learn/best-practices/>
-  
-   With respect to that, you should be sure to be explicit with your here representation on your data schema. You should give all planned details, and you should make adjustments when you feel to evolve your server with your desired schema.   
--}
-processQueryString :: String                        -- ^ GraphQL query argument as String.
-                   -> [(String,[String])]           -- ^ unique server object name to list of query reference names.
-                   -> [(String,[(String,String)])]  -- ^ unique server object name to list of valid scalar subfields (which are exactly named after database column names) and the subfield type.
-                   -> [(String,[String])]           -- ^ unique server object name to list of valid nested object subfields (which are named to your preference, though you must include these in the tuple list in the first argument list)
-                   -> [(String,[String])]           -- ^ unique server object name to list of database table names (which are exact references to table names).
-                   -> [(String,String,[String])]    -- ^ two database table names to list of from-to-and intermediate triplet strings as described above to identify all GraphQL relationships with database sequences.
-                   -> ([RootObject],[[String]])     -- ^ The return value is one tuple with server objects and list with grouped sql query strings.
-processQueryString str svrobjs sss sos sodn sor = checkObjectsToSql sss sos sodn sor $ checkStringToObjects svrobjs $ QP.processString str
-
+import Model.ServerObjectTypes (RootObject)
 
+                                  
 {- |
-   This method is same as above, but another second argument is a string to give variables in your query.
-
-   The expected variables string is json syntax.
-
-   Valid types are Text, ByteString, Int, Double, Rational, Bool, Day, TimeOfDay, or UTCTime when declaring variable types at the beginning of the query.
-
-   There are additional thrown exceptions:
-
-   * MissingVariableValueException (when we are missing variables in the variables-value string to the query)
-   * InvalidVariableNameException (when we cannot find a variable in the query with given variables-value string)
-   * MismatchedVariableTypeException (when query variable type is not matching object scalar type)
-   * InvalidVariableTypeException (when variable type is invalid or missing)
-   * ReadVariablesException (when the variables json string syntax is incorrect or was not correctly read)
-   * VariablesSyntaxException (when the query variables declaration is invalid syntax)
-
-   NOTE: the variable-value json string is variable names without $ at the beginning while all other calls are with preceding $.
--}
-processQueryStringWithVariables :: String                        -- ^ This is the GraphQL query
-                                -> String                        -- ^ This is the variables string
-                                -> [(String,[String])]           -- ^ unique server object name to list of query reference names.
-                                -> [(String,[(String,String)])]  -- ^ unique server object name to list of valid scalar subfields (which are exactly named after database column names) and the subfield type.
-                                -> [(String,[String])]           -- ^ unique server object name to list of valid nested object subfields (which are named to your preference, though you must include these in the tuple list in the first argument list)
-                                -> [(String,[String])]           -- ^ unique server object name to list of database table names (which are exact references to table names).
-                                -> [(String,String,[String])]    -- ^ two database table names to list of from-to-and intermediate triplet strings as described above to identify all GraphQL relationships with database sequences.
-                                -> ([RootObject],[[String]])     -- ^ The return value is one tuple with server objects and list with grouped sql query strings.
-processQueryStringWithVariables qry vars svrobjs sss sos sodn sor = checkObjectsToSqlWithVariables sss sos sodn sor dvars $ checkStringToObjectsWithVariables svrobjs dvars $ QP.processString qry
-                                                                      where
-                                                                        dvars = VP.parseVariables vars qry
+   This function is to parse, validate, and interpret your query with variables. If you don't have variables, you may pass an empty string.
 
-{- |
-     Except being nested in a monad, this funcion is same as above.
+   __Function return value:__
 
-     It is allowing you to use a json file to declare your server data schema.
+   The returned values are one tuple to contain information to pass into your database interface and to later reuse in below data processing function. 
+   The tuple is (PackagedObjects,SQLQueries). The second tuple member is a collection of queries. 
+   An example is given on this <https://github.com/jasonsychau/graphql-w-persistent page> to iterate the queries to your database.
+   The example is also showing how is the first member passed to the data processing function.
 
-     The json format is a list of objects. You detail your schema with a list of objects to refer to server objects...
+   __Schema:__
 
-     __Instructions to give server schema:__
+   The schema json file is formated as one json object to describe the GraphQL objects and the object heirarchy.
+   Only "PrimitiveObjects" are valid descendants to "ParentalObjects".
+   Only the shared object fields and shared scalar fields are parental object fields.
+   If a parental object is a declared field from a primitive object, all descendants are supposed to be declared in the primitive object database relationships.
+   When declaring any primitive or parental object, the pseudonym is supposed to list all possible reference words to the object (in root object or nested object)
+   Primitive objects are expected to have a unique "id" column in the declared database table.
+   Database relationships are defined as an ordered sequence from the identity table to the target association table. 
+   Scalars and database relationships are declared as they are read in database schema.
+   The order is identity table, identity table join field(s), target table, target table join field(s), then (multiple) triplets (of intermediate table, intermediate table to-join field, then intermediate table from-join field in order of nearness from identity table) if relevant.
+   If multiple fields are defining the join, one declares every field with a space " " separation.
+   For example, the declaration is [A,"a b", B, "c d"] if the join condition is A.a=B.c and A.b = B.d.
+   You can add schema associations as declaring more fields in the primitive objects.
 
-     The every object is...
+   __Scalar fields:__
 
-     (1) "servername" is a string to name the server object
-     (2) "pseudonyms" is a list of string to give all query reference
-     (3) "scalarfields" is a list of objects that are scalar name under "name" and scalar type under "type"
-     (4) "objectfields" is a list of nested object fields
-     (5) "databasetables" is a list of tables in your database
-     (6) "databaserelationships" is a list of database relationships from this refering table to another table
+   Scalar fields are declared with a type, and they are cast to corresponding JSON format when making the GraphQL result.
+   Valid scalar field types are Text, ByteString, Int, Double, Rational, Bool, Day, TimeOfDay, or UTCTime.
 
-     NOTE: You do not need to repeat databaserelationships in any objects. A relationship is given once, and more is redundant... 
+   __Function exceptions:__
 
-     NOTE: You should put every objectfields value in some pseudonym list value.
+   Exceptions are returned when error is faced. This method returns errors of:
 
-     NOTE: multiple fields are separated by a space in defining the relationships. For example, the relationship is [A,"a b", B, "c d"] if A.a=B.c and A.b = B.d.
+    * SyntaxException (when there is a problem with the given GraphQL query syntax)
+    * ParseFragmentException (when there is a problem with a Fragment syntax)
+    * EmptyQueryException (when the query is left blank)
+    * InvalidObjectException (when there is problem in nested object syntax, an object is not recognized, or server data is misinterpreted)
+    * InvalidObjectSubFieldException (when a subfield is requested from nested object that is not having ownership of the subfield)
+    * InvalidScalarException (when there is syntax error in listing scalar fields, or server data is misinterpreted)
+    * NullArgumentException (when a transformation is set but no argument is given though we do not yet support transformations) 
+    * CreatingSqlQueryObjectFieldsException (when there are too many nested object subfields than nested objects to hold them or when there is a problem with the aligning of server object relationship argument - that's the fifth schema argument)
+    * RelationshipConfigurationException (when the relationship schema fifth arugment is incorrect number of String values, when an unrecognized pairing is found, or when two table field cardinalities are not same)
+    * FailedObjectEqualityException (when we could not match identical queries)
+    * DuplicateRootObjectsException (when there is an overlapping query)
+ 
+    * ImportSchemaException (when there is a problem with reading your schema)
+    * ImportSchemaServerNameException (when there is a problem with reading your servername argument)
+    * ImportSchemaPseudonymsException (when there is a problem with reading your pseudonyms list argument)
+    * ImportSchemaScalarFieldsException (when there is a problem with reading your scalarfields list argument)
+    * ImportSchemaObjectFieldsException (when there is a problem with reading your objectfields list argument)
+    * ImportSchemaDatabaseTablesException (when there is a problem with reading your databasetables list argument)
+    * ImportSchemaDatabaseRelationshipsException (when there is a problem with reading your databaserelationships list argument)
+ 
+    * MissingVariableValueException (when we are missing variables in the variables-value string to the query)
+    * InvalidVariableNameException (when we cannot find a variable in the query with given variables-value string)
+    * MismatchedVariableTypeException (when query variable type is not matching object scalar type)
+    * InvalidVariableTypeException (when variable type is invalid or missing)
+    * ReadVariablesException (when the variables json string syntax is incorrect or was not correctly read)
+    * VariablesSyntaxException (when the query variables declaration is invalid syntax)
 
-     Here is an example:
+   __Schema format example:__
 
-     @
-      [
+   Here is an example schema to look at formatting:
+   @
+    {
+      "ParentalObjects":[
         {
-          "servername": "Person",
-          "pseudonyms": [
+          "ServerName":"Taxonomy",
+          "Pseudonyms":[
+            "taxonomy",
+            "Taxonomy"
+          ],
+          "ServerChildren":[
+            "Breed",
+            "Species",
+            "Family",
+            "Genus"
+          ]
+        }
+      ],
+      "PrimitiveObjects":[
+        {
+          "ServerName": "Person",
+          "Pseudonyms": [
             "person",
             "Person",
             "owner"
           ],
-          "scalarfields": [
+          "ScalarFields": [
             {
-              "name": "id",
-              "type": "Int"
+              "Name": "id",
+              "Type": "Int"
             },
             {
-              "name": "name",
-              "type": "Text"
+              "Name": "name",
+              "Type": "Text"
             },
             {
-              "name": "gender",
-              "type": "Int"
+              "Name": "gender",
+              "Type": "Int"
             }
           ],
-          "objectfields": [
-            "pet"
+          "ObjectFields": [
+            "pet",
+            "breed",
+            "species",
+            "genus",
+            "family",
+            "taxonomy"
           ],
-          "databasetables": [
+          "DatabaseTable": "person",
+          "DatabaseRelationships": [
+            ["person","id","pet","id","pet_ownership","owner_id","animal_id"],
+            ["person","id","breed","id","pet_ownership","owner_id","animal_id","pet","id","id","pet_type","pet_id","breed_id"],
+            ["person","id","species","id","pet_ownership","owner_id","animal_id","pet","id","id","pet_type","pet_id","breed_id","breed","id","species_id"],
+            ["person","id","genus","id","pet_ownership","owner_id","animal_id","pet","id","id","pet_type","pet_id","breed_id","breed","id","species_id","species","id","genus_id"],
+            ["person","id","family","id","pet_ownership","owner_id","animal_id","pet","id","id","pet_type","pet_id","breed_id","breed","id","species_id","species","id","genus_id","genus","id","family_id"]
+          ]
+        },
+        {
+          "ServerName": "Family",
+          "Pseudonyms": [
+            "Family",
+            "family"
+          ],
+          "ScalarFields": [
+            {
+              "Name": "id",
+              "Type": "Int"
+            },
+            {
+              "Name": "name",
+              "Type": "Text"
+            }
+          ],
+          "ObjectFields": [
+            "genus",
+            "species",
+            "breed",
+            "pet",
             "person"
           ],
-          "databaserelationships": [
-            ["person","id","pet","id","pet_ownership","owner_id","animal_id"]
+          "DatabaseTable": "family",
+          "DatabaseRelationships": [
+            ["family","id","person","id","genus","family_id","id","species","genus_id","id","breed","species_id","id","pet_type","breed_id","pet_id","pet_ownership","animal_id","owner_id"],
+            ["family","id","pet","id","genus","family_id","id","species","genus_id","id","breed","species_id","id","pet_type","breed_id","pet_id"],
+            ["family","id","genus","family_id"],
+            ["family","id","species","genus_id","genus","family_id","id"],
+            ["family","id","breed","species_id","genus","family_id","id","species","genus_id","id"]
           ]
         },
         {
-          "servername": "Pet",
-          "pseudonyms": [
+          "ServerName": "Genus",
+          "Pseudonyms": [
+            "Genus",
+            "genus"
+          ],
+          "ScalarFields": [
+            {
+              "Name": "id",
+              "Type": "Int"
+            },
+            {
+              "Name": "name",
+              "Type": "Text"
+            }
+          ],
+          "ObjectFields": [
+            "family",
+            "species",
+            "breed",
             "pet",
-            "Pet"
+            "person"
           ],
-          "scalarfields": [
+          "DatabaseTable": "genus",
+          "DatabaseRelationships": [
+            ["genus","id","person","id","species","genus_id","id","breed","species_id","id","pet_type","breed_id","pet_id","pet_ownership","animal_id","owner_id"],
+            ["genus","id","pet","id","species","genus_id","id","breed","species_id","id","pet_type","breed_id","pet_id"],
+            ["genus","family_id","family","id"],
+            ["genus","id","species","genus_id"],
+            ["genus","id","breed","species_id","species","genus_id","id"]
+          ]
+        },
+        {
+          "ServerName": "Species",
+          "Pseudonyms": [
+            "Species",
+            "species"
+          ],
+          "ScalarFields": [
             {
-              "name": "id",
-              "type": "Int"
+              "Name": "id",
+              "Type": "Int"
             },
             {
-              "name": "name",
-              "type": "Text"
+              "Name": "name",
+              "Type": "Text"
+            }
+          ],
+          "ObjectFields": [
+            "family",
+            "genus",
+            "breed",
+            "pet",
+            "person"
+          ],
+          "DatabaseTable": "species",
+          "DatabaseRelationships": [
+            ["species","id","person","id","breed","species_id","id","pet_type","breed_id","pet_id","pet_ownership","animal_id","owner_id"],
+            ["species","id","pet","id","breed","species_id","id","pet_type","breed_id","pet_id"],
+            ["species","id","breed","species_id"],
+            ["species","genus_id","genus","id"],
+            ["species","id","family","genus_id","genus","species_id","id"]
+          ]
+        },
+        {
+          "ServerName": "Breed",
+          "Pseudonyms": [
+            "Breed",
+            "breed"
+          ],
+          "ScalarFields": [
+            {
+              "Name": "id",
+              "Type": "Int"
             },
             {
-              "name": "gender",
-              "type": "Int"
+              "Name": "name",
+              "Type": "Text"
             }
           ],
-          "objectfields": [
-            "owner"
+          "ObjectFields": [
+            "family",
+            "genus",
+            "species",
+            "pet",
+            "person"
           ],
-          "databasetables": [
-            "pet"
+          "DatabaseTable": "breed",
+          "DatabaseRelationships": [
+            ["breed","id","person","id","pet_type","breed_id","pet_id","pet_ownership","animal_id","owner_id"],
+            ["breed","id","pet","id","pet_type","breed_id","pet_id"],
+            ["breed","species_id","species","id"],
+            ["breed","species_id","genus","id","species","id","genus_id"],
+            ["breed","species_id","family","id","species","id","genus_id","genus","id","family_id"]
+          ]
+        },
+        {
+          "ServerName": "Pet",
+          "Pseudonyms": [
+            "pet",
+            "Pet"
           ],
-          "databaserelationships": [
-            ["pet","id","person","id","pet_ownership","animal_id","owner_id"]
+          "ScalarFields": [
+            {
+              "Name": "id",
+              "Type": "Int"
+            },
+            {
+              "Name": "name",
+              "Type": "Text"
+            },
+            {
+              "Name": "gender",
+              "Type": "Int"
+            }
+          ],
+          "ObjectFields": [
+            "owner",
+            "breed",
+            "species",
+            "genus",
+            "family",
+            "taxonomy"
+          ],
+          "DatabaseTable": "pet",
+          "DatabaseRelationships": [
+            ["pet","id","person","id","pet_ownership","animal_id","owner_id"],
+            ["pet","id","breed","id","pet_type","pet_id","breed_id"],
+            ["pet","id","species","id","pet_type","pet_id","breed_id","breed","id","species_id"],
+            ["pet","id","genus","id","pet_type","pet_id","breed_id","breed","id","species_id","species","id","genus_id"],
+            ["pet","id","family","id","pet_type","pet_id","breed_id","breed","id","species_id","species","id","genus_id","genus","id","family_id"]
           ]
         }
       ]
-     @
-
-     __To implement server type heirarchy:__
-   
-     * add new object to list,
-     * give the children intersection scalar fields in the scalarfields argument,
-     * give the children intersection object fields in the objectfields argument,
-     * and add all referring children database table names to the databasetables argument.
-
-     You should not need more cases in the databaserelationships argument, but you may find a child database table and object field database table pair that is not included. If you don't include these relationships, an error is thrown.
+    }
+   @
 
-     The exceptions thrown with this function are same as above function processQueryString, but there are a few more...
+   __Closing remark:__
 
-     * ImportSchemaException (when there is a problem with reading your schema)
-     * ImportSchemaServerNameException (when there is a problem with reading your servername argument)
-     * ImportSchemaPseudonymsException (when there is a problem with reading your pseudonyms list argument)
-     * ImportSchemaScalarFieldsException (when there is a problem with reading your scalarfields list argument)
-     * ImportSchemaObjectFieldsException (when there is a problem with reading your objectfields list argument)
-     * ImportSchemaDatabaseTablesException (when there is a problem with reading your databasetables list argument)
-     * ImportSchemaDatabaseRelationshipsException (when there is a problem with reading your databaserelationships list argument)
+   As the last remark, I'll turn attention to a quote from specifications.
 
-   As a final note, we turn our attention to what is posted on the official GraphQL docs:
-  
    @"In contrast, GraphQL only returns the data that's explicitly requested, so new capabilities can be added via new types and new fields on those types without creating a breaking change. This has lead to a common practice of always avoiding breaking changes and serving a versionless API."@ - <https://graphql.github.io/learn/best-practices/>
   
-   With respect to that, you should be sure to be explicit with your here representation on your data schema. You should give all planned details, and you should make adjustments when you feel to evolve your server with your desired schema.   
+   With respect to that, you should be sure to be explicit with your schema representation. You should give all planned details, and you should make adjustments when you feel to evolve your server to make graph-like associations.   
 -}
-processQueryStringWithJson :: (MonadIO m)
-                           => String                       -- ^ This is the GraphQL query
-                           -> FilePath                     -- ^ This is the filepath to your server schema json file
-                           -> m ([RootObject],[[String]])  -- ^ The return value is a monad of one tuple with server objects and list with grouped sql query strings.
-processQueryStringWithJson qry fp = do
-                                  (svrobjs,sss,sos,sodn,sor) <- IO.liftIO $ JP.fetchArguments fp
-                                  return $ checkObjectsToSql sss sos sodn sor $ checkStringToObjects svrobjs $ QP.processString qry
-
-
+processQueryString :: (MonadIO m)
+                   => FilePath                                    -- ^ This is the path to schema json file
+                   -> String                                      -- ^ This is the GraphQL query
+                   -> String                                      -- ^ This is the variables string
+                   -> m ([(RootObject,[[String]])],[[String]])  -- ^ The return value is a monad of one tuple with package objects and list with grouped sql query strings.
+processQueryString fp qry vars = do
+                                  (svrobjs,sss,sos,sodn,sor,soa) <- liftIO $ fetchArguments fp
+                                  let dvars = parseVariables vars qry
+                                  let str = processString qry
+                                  let objs = if (validateQuery str)==True then (parseStringToObjects str svrobjs soa dvars) else throw SyntaxException
+                                  let robjs = mergeDuplicatedRootObjects $ replaceObjectsVariables sss objs dvars
+                                  let (tbls,qrys) = if (checkObjectsAttributes robjs sss sos soa)==True then (makeSqlQueries robjs sodn sor soa) else (throw InvalidObjectSubFieldException)
+                                  return (zip robjs tbls,qrys)
 {- |
-   This method is same as above, but another third argument is a string to give variables in your query.
-
-   The expected variables string is json syntax.
-
-   Valid types are Text, ByteString, Int, Double, Rational, Bool, Day, TimeOfDay, or UTCTime when declaring variable types at the beginning of the query.
-
-   There are additional thrown exceptions:
-
-   * MissingVariableValueException (when we are missing variables in the variables-value string to the query)
-   * InvalidVariableNameException (when we cannot find a variable in the query with given variables-value string)
-   * MismatchedVariableTypeException (when query variable type is not matching object scalar type)
-   * InvalidVariableTypeException (when variable type is invalid or missing)
-   * ReadVariablesException (when the variables json string syntax is incorrect or was not correctly read)
-   * VariablesSyntaxException (when the query variables declaration is invalid syntax)
-
-   NOTE: the variable-value json string is variable names without $ at the beginning while all other calls are with preceding $.
--}
-processQueryStringWithJsonAndVariables :: (MonadIO m)
-                                       => String                       -- ^ This is the GraphQL query
-                                       -> String                       -- ^ This is the variables string
-                                       -> FilePath                     -- ^ This is the filepath to your server schema json file
-                                       -> m ([RootObject],[[String]])  -- ^ The return value is a monad of one tuple with server objects and list with grouped sql query strings.
-processQueryStringWithJsonAndVariables qry vars fp = do
-                                                  (svrobjs,sss,sos,sodn,sor) <- IO.liftIO $ JP.fetchArguments fp
-                                                  let dvars = VP.parseVariables vars qry
-                                                  return $ checkObjectsToSqlWithVariables sss sos sodn sor dvars $ checkStringToObjectsWithVariables svrobjs dvars $ QP.processString qry 
+    After casting all database results to Text (example is given in <https://github.com/jasonsychau/graphql-w-persistent examples> page), you may use this function to process data to GraphQL format.
 
-{- |
-    This is the function to call after casting PersistValues to Text from processQueryString of which you may find on my examples <https://github.com/jasonsychau/graphql-w-persistent page>.
-    
-    The ordered arguments are:
-    
-     * all the data that is cast to Text type
-     * an unmodified copy of the RootObject list that is returned from processing the query string.
+    The second argument is the package objects given from function processQueryString.
     
     The return result is a string to resemble the GraphQL return value.
 
-    Current implementation is to cast all values to Text since arbitrary columns data types are not inferred, though next update is changing this limitation.
-
-
-    When an error is encountered, an uncaught exception is thrown. The exceptions thrown are of:
-
-    * InvalidObjectException (when server data is misinterpreted or an unrecognized server object is met)
-    * InvalidScalarException (when server data is misinterpreted)
-    * EOFDataProcessingException (when the given data is shorter than expected in reference to the given serve objects)
-    * InvalidArgumentException (when there is an internal argument error - you should not observe this)
-    * InvalidVariableTypeException (when an unrecognized base data type is met)
-    * InvalidObjectScalarFieldException (when an unrecognized object-scalar pair is met)
--}
-processPersistentData :: [(String,[(String,String)])]  -- ^ unique server object name to list of valid scalar subfields (which are exactly named after database column names) and the subfield type.
-                      -> [[[[Text]]]]                  -- ^ database query return value as casted to only Text data types and with no other alterations (a list of GraphQL-grouped results list of SQL query results list of data row lists)
-                      -> [RootObject]                  -- ^ unmodified server objects that was given by the previous processQueryString function.
-                      -> String                        -- ^ The return value is a string type to describe the GraphQL-organized return values.
-processPersistentData sss dt ro = DP.processReturnedValues sss ro dt
-
-{- | 
-    This is a json version from the above function. It is also wrapped in a monad
+    These are the exceptions returned from this function:
 
-    The exceptions thrown with this function are same as above function, but there are a few more...
+     * InvalidObjectException (when server data is misinterpreted or an unrecognized server object is met)
+     * InvalidScalarException (when server data is misinterpreted)
+     * EOFDataProcessingException (when the given data is shorter than expected in reference to the given serve objects)
+     * InvalidArgumentException (when there is an internal argument error - you should not observe this)
+     * InvalidVariableTypeException (when an unrecognized base data type is met)
+     * InvalidObjectScalarFieldException (when an unrecognized object-scalar pair is met)
 
      * ImportSchemaException (when there is a problem with reading your schema)
      * ImportSchemaServerNameException (when there is a problem with reading your servername argument)
@@ -404,11 +372,12 @@      * ImportSchemaDatabaseTablesException (when there is a problem with reading your databasetables list argument)
      * ImportSchemaDatabaseRelationshipsException (when there is a problem with reading your databaserelationships list argument)
 -}
-processPersistentDataWithJson :: (MonadIO m)
-                              => FilePath      -- ^ This is the file path to schema json
-                              -> [[[[Text]]]]  -- ^ This is the unmodified Persistent database query return value (a list of GraphQL-grouped results list of SQL query results list of data row lists).
-                              -> [RootObject]  -- ^ This is the unmodified server objects that was composed from previous processQueryString function.
-                              -> m String      -- ^ The return value is a monad of string type to describe the GraphQL-organized return values.
-processPersistentDataWithJson fp dt ro = do
-                                      (_,sss,_,_,_) <- IO.liftIO $ JP.fetchArguments fp
-                                      return $ DP.processReturnedValues sss ro dt
+processQueryData :: (MonadIO m)
+                 => FilePath                   -- ^ This is the path to schema json file
+                 -> [(RootObject,[[String]])]  -- ^ This is the package objects that is from processQueryString function.
+                 -> [[[[Text]]]]               -- ^ This is the database query results value in the same order and after casting to Text values.
+                 -> m String                   -- ^ The return value is a monad of string type to describe the GraphQL-organized return values.
+processQueryData fp cc dt = do
+                              (_,sss,_,sodn,_,soa) <- liftIO $ fetchArguments fp
+                              let (ro,tb) = unzip cc
+                              return $ processReturnedValues sss sodn soa ro tb dt
− src/GraphQLHelper.hs
@@ -1,23 +0,0 @@-module GraphQLHelper where
-
-import qualified Control.Exception as E
-import qualified Components.Parsers.QueryParser as QP
-import qualified Components.ObjectHandlers.ServerObjectValidator as SOV
-import qualified Components.QueryComposers.SQLQueryComposer as QC
-import qualified Components.ObjectHandlers.ServerObjectTrimmer as SOT
-import Model.ServerObjectTypes
-import Model.ServerExceptions
-
-
-checkStringToObjects :: [(String,[String])] -> String -> [RootObject]
-checkStringToObjects svrobjs str = if (QP.validateQuery str)==True then (QP.parseStringToObjects str svrobjs []) else E.throw SyntaxException
-checkObjectsToSql :: [(String,[(String,String)])] -> [(String,[String])] -> [(String,[String])] -> [(String,String,[String])] -> [RootObject] -> ([RootObject],[[String]])
-checkObjectsToSql sss sos sodn sor ros = if (SOV.checkObjectsAttributes reducedRobjs sss sos)==True then (reducedRobjs,QC.makeSqlQueries reducedRobjs sodn sor) else (E.throw InvalidObjectException)
-                                         where reducedRobjs = SOT.mergeDuplicatedRootObjects ros
-checkStringToObjectsWithVariables :: [(String,[String])] -> [(String,String,String)] -> String -> [RootObject]
-checkStringToObjectsWithVariables svrobjs vars str = if (QP.validateQuery str)==True then (QP.parseStringToObjects str svrobjs vars) else E.throw SyntaxException
-checkObjectsToSqlWithVariables :: [(String,[(String,String)])] -> [(String,[String])] -> [(String,[String])] -> [(String,String,[String])] -> [(String,String,String)] -> [RootObject] -> ([RootObject],[[String]])
-checkObjectsToSqlWithVariables sss sos sodn sor vars ros = if (SOV.checkObjectsAttributes valueObjects sss sos)==True then (valueObjects,QC.makeSqlQueries valueObjects sodn sor) else (E.throw InvalidObjectSubFieldException)
-                                    where
-                                        reducedObjects = SOT.mergeDuplicatedRootObjects ros
-                                        valueObjects = SOV.replaceObjectsVariables sss reducedObjects vars
src/Model/ServerExceptions.hs view
@@ -1,3 +1,10 @@+{- |
+Module      : Model.ServerExceptions
+Description : Here are exceptions for debugging.
+License     : IPS
+Maintainer  : jasonsychau@live.ca
+Stability   : provisional
+-}
 module Model.ServerExceptions where
 
 import Control.Exception
@@ -5,7 +12,7 @@ 
 data QueryException = SyntaxException |
                       VariableException | 
-                      ParseFragmentException | 
+                      ParseFragmentException |
                       EmptyQueryException | 
                       InvalidObjectException | 
                       InvalidScalarException |
@@ -31,6 +38,7 @@                       ImportSchemaObjectFieldsException |
                       ImportSchemaDatabaseTablesException |
                       ImportSchemaDatabaseRelationshipsException |
+                      ImportSchemaChildrenException |
                       MissingVariableValueException |
                       InvalidVariableNameException |
                       MismatchedVariableTypeException |
@@ -40,5 +48,20 @@                       ValueInterpretationException |
                       InvalidDirectiveException
   deriving Show
+  
 
-instance Exception QueryException+                      -- InvalidObjectNestedObjectFieldException | 
+                      -- InvalidObjectScalarFieldException | 
+                      -- InvalidAttributeTransformation |
+                      -- CreatingSqlQueryObjectsException |
+                      -- TooManyTablesException |
+                      -- EmptyRowException |
+                      -- Foundlinebreakexception |
+
+instance Exception QueryException
+
+-- use Control.Exception.assert to make your unit tests.
+-- simply use throw SyntaxException
+-- can I catch from main block?
+-- you can catch an exception and display message at next page.
+-- TODO: abstract read ServerObject: if read is wrong we catch and throw read server object error
src/Model/ServerObjectTypes.hs view
@@ -1,3 +1,10 @@+{- |
+Module      : Model.ServerObjectTypes
+Description : Here is the data types for the server objects.
+License     : IPS
+Maintainer  : jasonsychau@live.ca
+Stability   : provisional
+-}
 module Model.ServerObjectTypes where
 
 
@@ -12,7 +19,10 @@ type ServerObject = String
 type SubSelection = Maybe ScalarType
 type SubFields = [Field]
-type Field = Either ScalarType NestedObject
+type Field = Either ScalarType FieldObject
+type FieldObject = Either NestedObject InlinefragmentObject
+data InlinefragmentObject = InlinefragmentObject ServerObject SubFields
+                    deriving Show
 
 -- | ScalarTypes are the other subfield type. They are also found at object attributes.
 data ScalarType = ScalarType Alias Name Transformation Argument