QueryRunner.purs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. module LinkedIn.QueryRunner where
  2. import Prelude
  3. import Control.Alt ((<|>))
  4. import Control.Monad.Except (ExceptT(..), mapExceptT, runExceptT, throwError)
  5. import Data.Array as A
  6. import Data.Either (Either(..), note)
  7. import Data.Generic.Rep (class Generic)
  8. import Data.List.Types (NonEmptyList)
  9. import Data.Maybe (Maybe(..))
  10. import Data.Show.Generic (genericShow)
  11. import Data.Traversable (traverse)
  12. import Effect (Effect)
  13. import LinkedIn.Queryable (queryAllNodes, queryOneNode)
  14. import Web.DOM (Node)
  15. import Web.DOM.Node as N
  16. import Web.DOM.NodeList as NL
  17. import Web.DOM.Text as T
  18. data QueryError =
  19. QNodeNotFoundError String
  20. | QNodeListNotFoundError String
  21. | QNodeUnexpectedType String String
  22. | QTextNotFoundError
  23. | QChooseError
  24. derive instance Generic QueryError _
  25. derive instance Eq QueryError
  26. instance Show QueryError where
  27. show = genericShow
  28. type QueryRunner a = Node → ExceptT QueryError Effect a
  29. runQuery ∷ ∀ a. ExceptT QueryError Effect a → Effect (Either QueryError a)
  30. runQuery = runExceptT
  31. ignoreNotFound ∷ ∀ a f. Functor f ⇒ ExceptT QueryError f a → ExceptT QueryError f (Maybe a)
  32. ignoreNotFound = mapExceptT (map ignoreNotFound')
  33. where
  34. ignoreNotFound' = case _ of
  35. (Left (QNodeNotFoundError _ )) -> Right Nothing
  36. (Left (QNodeListNotFoundError _ )) -> Right Nothing
  37. (Left q) -> Left q
  38. (Right n') -> Right (Just n')
  39. ignoreErrors ∷ ∀ a f. Functor f ⇒ ExceptT QueryError f a → ExceptT QueryError f (Maybe a)
  40. ignoreErrors = mapExceptT (map ignoreErrors')
  41. where
  42. ignoreErrors' = case _ of
  43. (Left _) -> Right Nothing
  44. (Right n') -> Right (Just n')
  45. queryOne ∷ String → QueryRunner Node
  46. queryOne selector node = ExceptT $ do
  47. maybeNode <- queryOneNode selector node
  48. pure $ note (QNodeNotFoundError selector) maybeNode
  49. queryText ∷ Int -> QueryRunner Node
  50. queryText idx n = ExceptT $ do
  51. children <- N.childNodes n
  52. childrenArr <- NL.toArray children
  53. let
  54. maybeText n' = do
  55. _ <- T.fromNode n'
  56. pure $ n'
  57. allTexts = A.mapMaybe maybeText childrenArr
  58. pure $ note QTextNotFoundError $ A.index allTexts idx
  59. queryAll ∷ String → QueryRunner (NonEmptyList Node)
  60. queryAll selector node = ExceptT $ do
  61. maybeNodes <- queryAllNodes selector node
  62. pure $ note (QNodeListNotFoundError selector) maybeNodes
  63. subQueryMany ∷ ∀ a. QueryRunner a → String → QueryRunner (NonEmptyList a)
  64. subQueryMany query selector n = traverse query =<< queryAll selector n
  65. subQueryOne ∷ ∀ a. QueryRunner a → String → QueryRunner a
  66. subQueryOne query selector n = query =<< queryOne selector n
  67. chooseOne ∷ ∀ a t m. Monad m ⇒ (t → ExceptT QueryError m a) → (t → ExceptT QueryError m a) → (t → ExceptT QueryError m a)
  68. chooseOne q1 q2 n = do
  69. maybeN1 <- (ignoreErrors <<< q1) n
  70. maybeN2 <- (ignoreErrors <<< q2) n
  71. case maybeN1 <|> maybeN2 of
  72. Nothing -> throwError QChooseError
  73. Just n' -> pure n'
  74. chooseOne3 ∷ ∀ a t m.
  75. Monad m
  76. ⇒ (t → ExceptT QueryError m a)
  77. → (t → ExceptT QueryError m a)
  78. → (t → ExceptT QueryError m a)
  79. → (t → ExceptT QueryError m a)
  80. chooseOne3 q1 q2 q3 n = do
  81. maybeN1 <- (ignoreErrors <<< q1) n
  82. maybeN2 <- (ignoreErrors <<< q2) n
  83. maybeN3 <- (ignoreErrors <<< q3) n
  84. case maybeN1 <|> maybeN2 <|> maybeN3 of
  85. Nothing -> throwError QChooseError
  86. Just n' -> pure n'