packages feed

graphql-w-persistent 0.2.0.1 → 0.3.0.0

raw patch · 7 files changed

+85/−32 lines, 7 files

Files

ChangeLog.md view
@@ -30,12 +30,16 @@ 
 ## 0.1.0.7 -- 2018-10-26
 
-* json file schema
+* json file schema - stable
 
 ## 0.2.0.0 -- 2018-11-05
 
-* variables are available
+* variables are available...api change is schema changes
 
 ## 0.2.0.1 -- 2018-11-05
 
-* fix to accept empty variable arguments and default values+* fix to accept empty variable arguments and default values
+
+## 0.3.0.0 -- 2018-11-06
+
+* bug-fix to reenable relationship queries and casting returned values with Int, Rationals/Decimals, and Doubles...api change is arguments change to processing data function
graphql-w-persistent.cabal view
@@ -10,7 +10,7 @@ -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             0.2.0.1
+version:             0.3.0.0
 
 -- A short (one-line) description of the package.
 synopsis:            Haskell GraphQL query parser-interpreter-data processor.
src/Components/DataProcessors/PersistentDataProcessor.hs view
@@ -2,8 +2,8 @@ 
 import Data.Maybe
 import Data.Either
-import Data.Text (Text)
-import Text.JSON (encodeStrict,toJSObject,JSValue,showJSONs,toJSObject,showJSON)
+import Data.Text (Text,unpack)
+import Text.JSON
 import qualified Control.Exception as E
 import Model.ServerExceptions
 import Model.ServerObjectTypes
@@ -11,31 +11,36 @@ 
 
 -- with root objects we want one json representation of separate graphql results...
-processReturnedValues :: [RootObject] -> [[[[Text]]]] -> String
-processReturnedValues robjs rlts = encodeStrict $ toJSObject [("data", toJSObject [processReturnedValue x y | (x,y) <- zip robjs rlts])]
+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 :: RootObject -> [[[Text]]] -> (String, JSValue)
-processReturnedValue (NestedObject alias name _ _ sfs) rlts = (if (alias==Nothing) then name else (fromJust alias), showJSONs $ processSubFields sfs rlts)
+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 :: [Field] -> [[[Text]]] -> [JSValue]
-processSubFields _ [] = []
-processSubFields sfs rlts = foldr (\x y -> x++y) [] [((showJSON $ toJSObject $ composeGraphQlRow sfs $ fetchGraphQlRow typ):(processSubFields sfs [removeDataRow typ])) |typ<-rlts,(length typ)>0]
-composeGraphQlRow :: [Field] -> [[Text]] -> [(String,JSValue)]
-composeGraphQlRow [] ([]:t) = [] -- done
--- composeGraphQlRow _ [] = [] -- no data
-composeGraphQlRow _ ([]:t) = E.throw EOFDataProcessingException
-composeGraphQlRow [] _ = E.throw EOFDataProcessingException
-composeGraphQlRow (a:b) ((h:t):j)
-    | (isLeft a)==True = (((getScalarFieldLabel $ fromLeft (E.throw InvalidScalarException) a), (showJSON h)):(composeGraphQlRow b (removeNDataColumns 1 ((h:t):j))))
-    | otherwise = (((getNestedObjectFieldLabel $ fromRight (E.throw InvalidObjectException) a), showJSONs (processSubFields (getSubFields $ fromRight (E.throw InvalidObjectException) a) [pullNDataColumns nestedObjectFieldCount ((h:t):j)])):(composeGraphQlRow b (removeNDataColumns nestedObjectFieldCount ((h:t):j))))
+processSubFields :: [(String,[(String,String)])] -> String -> [Field] -> [[[Text]]] -> [JSValue]
+processSubFields _ _ _ [] = []
+processSubFields sss sobj sfs rlts = foldr (\x y -> x++y) [] [((showJSON $ toJSObject $ composeGraphQlRow sss sobj sfs $ fetchGraphQlRow typ):(processSubFields sss sobj sfs [removeDataRow typ])) |typ<-rlts,(length typ)>0]
+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)]
 removeDataRow :: [[Text]] -> [[Text]]
 removeDataRow rlts = [x | x<-rlts, (head x)/=(head $ 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]]
@@ -57,4 +62,21 @@ removeNDataColumns (-1) _ = E.throw EOFDataProcessingException
 removeNDataColumns _ [[]] = [[]]
 removeNDataColumns _ ([]:t) = E.throw EOFDataProcessingException
-removeNDataColumns cnt rslt = removeNDataColumns (cnt-1) [t | (h:t)<-rslt]+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/ServerObjectValidator.hs view
@@ -48,7 +48,7 @@     | (name==arg) = E.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 sobj (if ss/=Nothing then (replaceScalarVariable (findScalars sss sobj) vars $ fromJust ss) else Nothing) [replaceSubfieldVariables sss nsobj vars sf | sf<-sfs]) :: 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)
 isValue :: Maybe String -> Bool
 isValue Nothing = False
src/Components/QueryComposers/SQLQueryComposer.hs view
@@ -12,7 +12,9 @@ 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 $ translateServerObjectToDBName (getServerObject obj) sodn)==1 then (addSqlQueryFields (getSubFields obj) (M.fromList [((head $ translateServerObjectToDBName (getServerObject obj) sodn),1)]) ("select "++(head $ translateServerObjectToDBName (getServerObject obj) sodn)++(show 1)++".id,") (" from"++(makeSqlTablePhrase obj (head $ translateServerObjectToDBName (getServerObject obj) sodn) 1)) (" order by "++(head $ translateServerObjectToDBName (getServerObject obj) sodn)++(show 1)++".id asc") (((head $ translateServerObjectToDBName (getServerObject obj) sodn)++(show 1)):[]) [] [(head $ translateServerObjectToDBName (getServerObject obj) sodn)] 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<-(translateServerObjectToDBName (getServerObject obj) sodn)])
+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])
+                           where
+                             dbNames = translateServerObjectToDBName (getServerObject obj) sodn
 -- 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)
@@ -21,11 +23,12 @@ 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 CreatingSqlQueryObjectFieldsException
+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
     -- 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]
+    | 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
   where
     calcNewCounts :: String -> String -> M.Map String Int
@@ -53,4 +56,4 @@ 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 "++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 "++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 CreatingSqlQueryObjectFieldsException+completeTransition counts _ _ = E.throw RelationshipConfigurationException
src/GraphQL.hs view
@@ -374,7 +374,30 @@     * 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)
 -}
-processPersistentData :: [[[[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 dt ro = DP.processReturnedValues ro dt
+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
+
+    The exceptions thrown with this function are same as above function, but there are a few more...
+
+     * 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)
+-}
+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
src/Model/ServerExceptions.hs view
@@ -36,7 +36,8 @@                       MismatchedVariableTypeException |
                       InvalidVariableTypeException |
                       ReadVariablesException |
-                      VariablesSyntaxException
+                      VariablesSyntaxException |
+                      ValueInterpretationException
   deriving Show
 
                       -- InvalidObjectNestedObjectFieldException |