buuka/src/Data/Query.hs

89 lines
1.9 KiB
Haskell
Raw Normal View History

2021-01-02 09:09:38 +02:00
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
2021-10-27 20:46:23 +03:00
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
2021-01-02 09:09:38 +02:00
module Data.Query
(
2021-01-02 09:17:29 +02:00
-- * AST
Field(..)
2021-01-02 09:09:38 +02:00
-- * Combinators
2021-01-02 09:17:29 +02:00
, startsWith
2021-01-02 09:09:38 +02:00
, endsWith
2021-01-03 00:39:44 +02:00
, regex
2021-01-02 09:09:38 +02:00
, (.&&.)
-- * Evaluating queries
, evaluate
2021-01-03 00:39:44 +02:00
, predicate
2021-01-02 09:09:38 +02:00
)
where
import Data.Buuka
2021-01-03 09:52:38 +02:00
(BuukaEntry, title, url, _URL)
import Control.Lens
2021-01-02 09:09:38 +02:00
2021-01-03 00:23:43 +02:00
import Text.Regex.TDFA
((=~))
2021-01-02 09:09:38 +02:00
import Data.Functor.Foldable
2021-01-03 00:39:44 +02:00
(Fix(..), cata)
2021-01-02 09:09:38 +02:00
2021-01-03 08:33:44 +02:00
import Data.Text
(Text)
import qualified Data.Text as T
2021-01-02 09:09:38 +02:00
data Field a where
2021-01-03 08:33:44 +02:00
Url :: Field Text
Title :: Field Text
2021-01-02 09:09:38 +02:00
2021-01-03 00:14:52 +02:00
data QueryF f where
2021-01-03 08:33:44 +02:00
StartsWith :: Field Text -> Text -> QueryF f
EndsWith :: Field Text -> Text -> QueryF f
Regex :: Field Text -> Text -> QueryF f
2021-01-03 00:14:52 +02:00
And :: f -> f -> QueryF f
2021-10-27 20:46:23 +03:00
Pass :: QueryF f
2021-01-02 09:09:38 +02:00
deriving instance Functor QueryF
type Query = Fix QueryF
2021-10-27 20:46:23 +03:00
-- Query is a semigroup over the &&
instance Semigroup Query where
(<>) = (.&&.)
-- Identity is the constant true
instance Monoid Query where
mempty = Fix Pass
2021-01-03 08:33:44 +02:00
startsWith :: Field Text -> Text -> Query
2021-01-02 09:09:38 +02:00
startsWith field x = Fix (StartsWith field x)
2021-01-03 08:33:44 +02:00
endsWith :: Field Text -> Text -> Query
2021-01-02 09:09:38 +02:00
endsWith field x = Fix (EndsWith field x)
2021-01-03 08:33:44 +02:00
regex :: Field Text -> Text -> Query
2021-01-03 00:39:44 +02:00
regex field x = Fix (Regex field x)
2021-01-02 09:09:38 +02:00
(.&&.) :: Query -> Query -> Query
a .&&. b = Fix (And a b)
evaluate :: QueryF (BuukaEntry -> Bool) -> (BuukaEntry -> Bool)
evaluate = \case
2021-10-27 20:46:23 +03:00
StartsWith Url x -> has (url . _URL . prefixed x)
EndsWith Url x -> has (url . _URL . suffixed x)
StartsWith Title x -> has (title . _Just . prefixed x)
EndsWith Title x -> has (title . _Just . suffixed x)
2021-01-03 09:52:38 +02:00
Regex Url x -> \e -> (e ^. url . _URL) =~ x
Regex Title x -> \e -> maybe False (=~ x) $ e ^. title
2021-01-02 09:09:38 +02:00
And a b -> \e -> a e && b e
2021-10-27 20:46:23 +03:00
Pass -> const True
where
prefixed ps = prism' (ps <>) (T.stripPrefix ps)
suffixed qs = prism' (<> qs) (T.stripSuffix qs)
2021-01-03 00:39:44 +02:00
predicate :: Query -> BuukaEntry -> Bool
predicate = cata evaluate
2021-10-27 20:46:23 +03:00