-- |

-- Module      : JsonLogic.Evaluator

-- Description : Internal JsonLogic evaluator

-- Copyright   : (c) Marien Matser, Gerard van Schie, Jelle Teeuwissen, 2022

-- License     : MIT

-- Maintainer  : jelleteeuwissen@hotmail.nl

-- Stability   : experimental

module JsonLogic.Evaluator (apply) where

import Control.Monad.Except
import Data.Map as M
import JsonLogic.Json
import JsonLogic.Type

-- | Evaluate a rule

-- Evaluate an object or array, return other items.

apply :: Monad m => Operations m -> Rule -> Data -> Result m Json
apply :: Operations m -> Rule -> Rule -> Result m Rule
apply Operations m
ops o :: Rule
o@(JsonObject JsonObject
rules) Rule
dat = case JsonObject -> [(String, Rule)]
forall k a. Map k a -> [(k, a)]
M.toList JsonObject
rules of
  [(String
fName, Rule
fRule)] -> do
    case String -> Operations m -> Maybe (Function m Rule)
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup String
fName Operations m
ops of
      Maybe (Function m Rule)
Nothing -> Exception -> Result m Rule
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (Exception -> Result m Rule) -> Exception -> Result m Rule
forall a b. (a -> b) -> a -> b
$ String -> Exception
UnrecognizedOperation String
fName
      Just Function m Rule
f -> Function m Rule
f (Operations m -> Rule -> Rule -> Result m Rule
forall (m :: * -> *).
Monad m =>
Operations m -> Rule -> Rule -> Result m Rule
apply Operations m
ops) Rule
fRule Rule
dat
  -- A rule should always contain only one field

  [(String, Rule)]
_ -> Rule -> Result m Rule
forall (m :: * -> *) a. Monad m => a -> m a
return Rule
o -- throwError $ InvalidRule (M.keys rules)

apply Operations m
ops (JsonArray [Rule]
rules) Rule
dat = do
  [Rule]
result <- (Rule -> Result m Rule) -> [Rule] -> ExceptT Exception m [Rule]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (\Rule
rule -> Operations m -> Rule -> Rule -> Result m Rule
forall (m :: * -> *).
Monad m =>
Operations m -> Rule -> Rule -> Result m Rule
apply Operations m
ops Rule
rule Rule
dat) [Rule]
rules
  Rule -> Result m Rule
forall (m :: * -> *) a. Monad m => a -> m a
return (Rule -> Result m Rule) -> Rule -> Result m Rule
forall a b. (a -> b) -> a -> b
$ [Rule] -> Rule
JsonArray [Rule]
result
apply Operations m
_ Rule
x Rule
_ = Rule -> Result m Rule
forall (m :: * -> *) a. Monad m => a -> m a
return Rule
x