1 {-# LANGUAGE DeriveDataTypeable #-}
2 {-# LANGUAGE FlexibleContexts #-}
3 {-# LANGUAGE FlexibleInstances #-}
4 {-# LANGUAGE MultiParamTypeClasses #-}
5 {-# LANGUAGE StandaloneDeriving #-}
6 {-# LANGUAGE TypeFamilies #-}
7 module Hcompta.Model.Filter where
9 import Prelude hiding (filter)
10 import Control.Applicative (pure, (<$>), (<*>))
12 import qualified Data.Foldable
13 import Data.Foldable (Foldable(..))
14 import Data.Traversable (Traversable(..))
15 import Data.Monoid (Monoid(..))
16 import Data.Typeable ()
17 import Data.Text (Text)
18 -- import qualified Data.Text as Text
19 -- import qualified Data.Map.Strict as Data.Map
20 import Data.Map.Strict (Map)
21 import Text.Regex.TDFA ()
22 import Text.Regex.Base ()
23 import Text.Regex.TDFA.Text ()
25 import qualified Data.List.NonEmpty as NonEmpty
26 -- import Data.List.NonEmpty (NonEmpty(..))
27 import qualified Hcompta.Lib.Regex as Regex
28 import qualified Hcompta.Lib.Foldable as Lib.Foldable
29 import Hcompta.Lib.Regex (Regex)
30 import qualified Hcompta.Model.Date as Date ()
31 import Hcompta.Model.Date (Date)
32 import qualified Hcompta.Model.Account as Account
33 import Hcompta.Model.Account (Account)
34 -- import qualified Hcompta.Model.Date as Date
35 import qualified Hcompta.Calc.Balance as Calc.Balance
37 -- * Requirements' interface
42 unit_text :: a -> Text
47 ( Ord (Amount_Quantity a)
48 , Show (Amount_Quantity a)
49 , Show (Amount_Unit a)
50 , Unit (Amount_Unit a)
53 type Amount_Quantity a
55 amount_unit :: a -> Amount_Unit a
56 amount_quantity :: a -> Amount_Quantity a
58 instance (Amount a, Calc.Balance.Amount a)
59 => Amount (Calc.Balance.Amount_Sum a) where
60 type Amount_Quantity (Calc.Balance.Amount_Sum a) = Amount_Quantity a
61 type Amount_Unit (Calc.Balance.Amount_Sum a) = Amount_Unit a
62 amount_quantity = amount_quantity . Calc.Balance.amount_sum_balance
63 amount_unit = amount_unit . Calc.Balance.amount_sum_balance
67 class Amount (Posting_Amount p)
70 posting_account :: p -> Account
71 posting_amounts :: p -> Map (Amount_Unit (Posting_Amount p)) (Posting_Amount p)
73 -- ** Class 'Transaction'
75 class Posting (Transaction_Posting t)
76 => Transaction t where
77 type Transaction_Posting t
78 transaction_date :: t -> Date
79 transaction_description :: t -> Text
80 transaction_postings :: t -> Map Account [Transaction_Posting t]
84 class Amount (Balance_Amount b)
87 balance_account :: b -> Account
88 balance_amount :: b -> Balance_Amount b
90 instance (Amount a, Calc.Balance.Amount a)
91 => Balance (Account, Calc.Balance.Amount_Sum a) where
92 type Balance_Amount (Account, Calc.Balance.Amount_Sum a) = a
94 balance_amount = Calc.Balance.amount_sum_balance . snd
99 test :: p -> x -> Bool
102 :: (Foldable t, Test p x, Monoid x)
105 Data.Foldable.foldMap
106 (\x -> if test p x then x else mempty)
108 -- ** Type 'Test_Text'
111 = Test_Text_Exact Text
112 | Test_Text_Regex Regex
113 deriving (Eq, Show, Typeable)
115 instance Test Test_Text Text where
118 Test_Text_Exact m -> (==) m x
119 Test_Text_Regex m -> Regex.match m x
121 -- ** Type 'Test_Ord'
130 deriving (Data, Eq, Show, Typeable)
132 instance (Ord o, o ~ x)
133 => Test (Test_Ord o) x where
136 Test_Ord_Lt o -> (<) o x
137 Test_Ord_Lt_Eq o -> (<=) o x
138 Test_Ord_Gt o -> (>) o x
139 Test_Ord_Gt_Eq o -> (>=) o x
140 Test_Ord_Eq o -> (==) o x
142 -- ** Type 'Test_Num_Abs'
146 = Test_Num_Abs (Test_Ord n)
147 deriving (Data, Eq, Show, Typeable)
149 instance (Num n, Ord x, n ~ x)
150 => Test (Test_Num_Abs n) x where
151 test (Test_Num_Abs f) x = test f (abs x)
153 -- ** Type 'Test_Bool'
159 | And (Test_Bool p) (Test_Bool p)
160 | Or (Test_Bool p) (Test_Bool p)
162 instance Functor Test_Bool where
164 fmap f (Bool x) = Bool (f x)
165 fmap f (Not t) = Not (fmap f t)
166 fmap f (And t0 t1) = And (fmap f t0) (fmap f t1)
167 fmap f (Or t0 t1) = Or (fmap f t0) (fmap f t1)
168 instance Foldable Test_Bool where
169 foldr _ acc Any = acc
170 foldr f acc (Bool p) = f p acc
171 foldr f acc (Not t) = Data.Foldable.foldr f acc t
172 foldr f acc (And t0 t1) = Data.Foldable.foldr f (Data.Foldable.foldr f acc t0) t1
173 foldr f acc (Or t0 t1) = Data.Foldable.foldr f (Data.Foldable.foldr f acc t0) t1
174 instance Traversable Test_Bool where
175 traverse _ Any = pure Any
176 traverse f (Bool x) = Bool <$> f x
177 traverse f (Not t) = Not <$> traverse f t
178 traverse f (And t0 t1) = And <$> traverse f t0 <*> traverse f t1
179 traverse f (Or t0 t1) = Or <$> traverse f t0 <*> traverse f t1
180 instance Test p x => Test (Test_Bool p) x where
182 test (Bool p) x = test p x
183 test (Not t) x = not $ test t x
184 test (And t0 t1) x = test t0 x && test t1 x
185 test (Or t0 t1) x = test t0 x || test t1 x
187 bool :: Test p x => Test_Bool p -> x -> Bool
189 bool (Bool p) x = test p x
190 bool (Not t) x = not $ test t x
191 bool (And t0 t1) x = test t0 x && test t1 x
192 bool (Or t0 t1) x = test t0 x || test t1 x
194 -- ** Type 'Test_Unit'
197 = Test_Unit Test_Text
198 deriving (Eq, Show, Typeable)
200 instance Unit u => Test Test_Unit u where
201 test (Test_Unit f) = test f . unit_text
203 -- ** Type 'Test_Account'
206 = [Test_Account_Section]
208 data Test_Account_Section
209 = Test_Account_Section_Any
210 | Test_Account_Section_Skip
211 | Test_Account_Section_Text Test_Text
212 deriving (Eq, Show, Typeable)
214 instance Test Test_Account Account where
216 comp f (NonEmpty.toList acct)
218 comp :: [Test_Account_Section] -> [Account.Name] -> Bool
220 comp [Test_Account_Section_Skip] _ = True
225 Test_Account_Section_Any -> True
226 Test_Account_Section_Skip -> True
227 Test_Account_Section_Text m -> test m n
229 comp so@(s:ss) no@(n:ns) =
231 Test_Account_Section_Any -> comp ss ns
232 Test_Account_Section_Skip -> comp ss no || comp so ns
233 Test_Account_Section_Text m -> test m n && comp ss ns
236 -- ** Type 'Test_Amount'
244 { test_amount_quantity :: Test_Quantity (Amount_Quantity a)
245 , test_amount_unit :: Test_Unit
246 } deriving (Typeable)
247 deriving instance Amount a => Eq (Test_Amount a)
248 deriving instance Amount a => Show (Test_Amount a)
251 => Test (Test_Amount a) a where
252 test (Test_Amount fq fu) amt =
253 test fu (amount_unit amt) &&
254 test fq (amount_quantity amt)
256 -- ** Type 'Test_Posting'
259 => Test_Posting posting
260 = Test_Posting_Account Test_Account
261 | Test_Posting_Amount (Test_Amount (Posting_Amount posting))
262 | Test_Posting_Unit Test_Unit
265 -- Description Comp_String String
267 -- Account_Tag Comp_String String (Maybe (Comp_String, String))
268 -- Account_Balance Comp_Num Comp_Num_Absolute Amount
269 -- Depth Comp_Num Int
273 -- Tag Comp_String Tag.Name (Maybe (Comp_String, Tag.Value))
274 deriving instance Posting p => Eq (Test_Posting p)
275 deriving instance Posting p => Show (Test_Posting p)
278 => Test (Test_Posting p) p where
279 test (Test_Posting_Account f) p =
280 test f $ posting_account p
281 test (Test_Posting_Amount f) p =
282 Data.Foldable.any (test f) $ posting_amounts p
283 test (Test_Posting_Unit f) p =
284 Data.Foldable.any (test f . amount_unit) $ posting_amounts p
286 newtype Cross t = Cross t
287 instance (Transaction t, Transaction_Posting t ~ p, Posting p)
288 => Test (Test_Transaction t) (Cross p) where
291 (Test_Transaction_Description _) -> True
292 (Test_Transaction_Posting f) -> test f p
294 -- ** Type 'Test_Transaction'
297 => Test_Transaction t
298 = Test_Transaction_Description Test_Text
299 | Test_Transaction_Posting (Test_Posting (Transaction_Posting t))
301 deriving instance Transaction t => Eq (Test_Transaction t)
302 deriving instance Transaction t => Show (Test_Transaction t)
304 instance Transaction t
305 => Test (Test_Transaction t) t where
306 test (Test_Transaction_Description f) t =
307 test f $ transaction_description t
308 test (Test_Transaction_Posting f) t =
309 Data.Foldable.any (test f) $
310 Lib.Foldable.Composition $
311 transaction_postings t
313 -- ** Type 'Test_Balance'
317 = Test_Balance_Account Test_Account
318 | Test_Balance_Amount (Test_Amount (Balance_Amount b))
320 deriving instance Balance b => Eq (Test_Balance b)
321 deriving instance Balance b => Show (Test_Balance b)
324 => Test (Test_Balance b) b where
325 test (Test_Balance_Account f) b =
326 test f $ balance_account b
327 test (Test_Balance_Amount f) b =
328 test f $ balance_amount b