Last active
August 3, 2018 05:10
-
-
Save Woody88/8dd5510c0fe3f937ce6ec92903f965b5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module Salesforce.SOQL.Query where | |
| import Prelude | |
| import Control.Monad.Except | |
| import Control.Monad.Error.Class | |
| import Data.Either (Either(..)) | |
| import Data.Function.Uncurried (Fn4, runFn4) | |
| import Effect.Aff (Aff) | |
| import Effect.Aff.Compat (EffectFnAff, fromEffectFnAff) | |
| import Foreign (Foreign, MultipleErrors) | |
| import Foreign.Class (class Decode, decode) | |
| import Foreign.Generic (genericDecode, decodeJSON, defaultOptions) | |
| import Data.Generic.Rep (class Generic) | |
| import Data.Generic.Rep.Show (genericShow) | |
| import Salesforce.Types (Connection) | |
| newtype SOQL result = SOQL String | |
| data QueryError = QueryError String | SOQLParse MultipleErrors | |
| type QueryResult r = | |
| { totalSize :: Int | |
| , done :: Boolean | |
| , records :: Array (Record r) | |
| } | |
| newtype SOQLResult r = SOQLResult | |
| { totalSize :: Int | |
| , done :: Boolean | |
| , records :: Array r | |
| } | |
| newtype SOQLResult' = SOQLResult' | |
| { totalSize :: Int | |
| , done :: Boolean | |
| , records :: Foreign | |
| } | |
| derive instance genericSOQLResult :: Generic (SOQLResult r) _ | |
| derive instance genericSOQLResult' :: Generic SOQLResult' _ | |
| instance decodeSOQLResult :: Decode r => Decode (SOQLResult r) where | |
| decode = genericDecode $ defaultOptions {unwrapSingleConstructors = true} | |
| instance decodeSOQLResult' :: Decode SOQLResult' where | |
| decode = genericDecode $ defaultOptions {unwrapSingleConstructors = true} | |
| queryString :: forall r. Connection -> String -> Aff (Either QueryError (QueryResult r)) | |
| queryString conn q = fromEffectFnAff $ runFn4 queryString_ conn q (Left <<< QueryError) Right | |
| query :: forall result. Decode result => Connection -> SOQL result -> Aff (Either QueryError (Array result)) | |
| query conn soql = query' conn soql | |
| >>= (\eitherSOQL -> | |
| pure $ eitherSOQL | |
| >>= (\(SOQLResult r) -> pure $ r.records)) | |
| query' :: forall result. Decode result => Connection -> SOQL result -> Aff (Either QueryError (SOQLResult result)) | |
| query' conn soql = querySOQLResult conn soql | |
| >>= (\eitherSOQL -> | |
| pure $ eitherSOQL | |
| >>= (\(SOQLResult' q) -> decodeRecord q.records)) | |
| where | |
| decodeRecord :: forall r. Decode r => Foreign -> Either QueryError r | |
| decodeRecord rec = (parsingHandler <<< runExcept <<< decode $ rec) | |
| querySOQLResult :: forall result. Decode result => Connection -> SOQL result -> Aff (Either QueryError (SOQLResult')) | |
| querySOQLResult conn (SOQL q) = do | |
| eitherF <- fromEffectFnAff $ runFn4 query_ conn q (Left <<< QueryError) Right | |
| pure $ (eitherF >>= \x -> parsingHandler <<< runExcept <<< decode $ x) | |
| -- where | |
| -- decodeRecord :: forall r. Decode r => {totalSize :: Int, done :: Boolean , records :: Foreign} -> Either QueryError r | |
| -- decodeRecord res = (parsingHandler <<< runExcept <<< decode $ res.records) | |
| parsingHandler :: forall a. Decode a => Either MultipleErrors a -> Either QueryError a | |
| parsingHandler (Left x) = throwError $ SOQLParse x | |
| parsingHandler (Right x) = pure x | |
| -- where decodeSOQL = runExcept <<< decodeJSON | |
| -- decodeSOQL fv | |
| -- where decodeOpts = defaultOptions { unwrapSingleConstructors = true } | |
| -- decodeSOQL fail@(Left v) = fail | |
| -- decodeSOQL (Right json) = runExcept <<< genericDecodeJSON decodeOpts $ json | |
| {-- Type Related Issue | |
| we the function below there is an assumption that assumption that JSForce provides valid data of type `sobject`. | |
| And since it’s on the FFI boundary the compiler will trust you. | |
| Based on Robert this is often referred as the `TypeScript Problem` :) | |
| With generics, you replace the assumed type on the FFI declaration with `Foreign` and decode it in PureScript, giving it all the guarantees you would have if you had declared the data in PS (edited) | |
| Generics adds compile-time static type reflection and typeclass-based code generation. | |
| libraries needed `foreign-generic` + `generics-rep` | |
| --} | |
| foreign import queryString_ :: forall a b c sobject. Fn4 Connection a (String -> b) (QueryResult sobject -> b) (EffectFnAff b) | |
| foreign import query_ :: forall a b. Fn4 Connection a (String -> b) (Foreign -> b) (EffectFnAff b) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment