jsonlogic-0.1.0.0: src/JsonLogic/Operation/Data.hs
{-# LANGUAGE OverloadedLists #-}
-- |
-- Module : JsonLogic.Operation.Data
-- Description : Internal JsonLogic operations on objects and data
-- Copyright : (c) Marien Matser, Gerard van Schie, Jelle Teeuwissen, 2022
-- License : MIT
-- Maintainer : jelleteeuwissen@hotmail.nl
-- Stability : experimental
module JsonLogic.Operation.Data (dataOperations, var, missing, missingSome, preserve) where
import Data.Maybe
import JsonLogic.Json
import JsonLogic.Operation.Primitive
import JsonLogic.Operation.Utils
import JsonLogic.Type
dataOperations :: Monad m => Operations m
dataOperations = [var, missing, missingSome, preserve]
var, missing, missingSome :: Monad m => Operation m
var = ("var", evaluateVar)
missing = ("missing", evaluateMissing)
missingSome = ("missing_some", evaluateMissingSome)
preserve :: Monad m => Operation m
preserve = ("preserve", \_ rule _ -> return rule)
-- Evaluates a var
evaluateVar :: Monad m => Function m Json
evaluateVar evaluator param vars = do
res <- evaluator param vars
-- Extracts default value from array if it has one
let (j, def) = getJsonWithDefault res
case j of
-- Indexing using a floored double or index object using a string
i@(JsonNumber _) -> return $ fromMaybe def $ indexWithJson i vars
i@(JsonString _) -> return $ fromMaybe def $ indexWithJson i vars
-- null and empty array return the variables directly
JsonNull -> return vars
JsonArray [] -> return vars
-- Nested array, boolean and object always resort to default value
_ -> return def
-- | When var receives an array, the first item is the initial logic
-- If that logic fails then the second value is defaulted to
-- Any valuie after the second one is ignored
getJsonWithDefault :: Json -> (Json, Json)
getJsonWithDefault (JsonArray (x : y : _)) = (x, y)
getJsonWithDefault j = (j, JsonNull)
-- | Evaluates which elements are missing from the Json
evaluateMissing :: Monad m => Function m Json
evaluateMissing evaluator keys' vars = do
keys <- evaluator keys' vars
-- Only keep the missing values in the json array
return . JsonArray $ missingKeys keys vars
-- | Evaluates whether more than x items are missing from the original array
-- If so, it returns the entire list of missing items
-- Otherwise it returns an empty list
evaluateMissingSome :: Monad m => Function m Json
evaluateMissingSome evaluator (JsonArray [minKeys', keys']) vars = do
minKeys <- evaluateInt evaluator minKeys' vars
keys <- evaluator keys' vars
let miss = missingKeys keys vars
case keys of
-- Return result if at least x elements are missing or else an empty array
JsonArray js | length js - length miss >= minKeys -> return $ JsonArray []
JsonArray _ -> return $ JsonArray miss
-- If there is only a singleton as parameter, the length is 1
_ | 1 - length miss >= minKeys -> return $ JsonArray []
_ -> return $ JsonArray miss
-- The parameters are invalid
evaluateMissingSome _ json _ = throw $ "Error: missing_some expects an array of two arguments, instead it got: " ++ show json
-- | Returns the missing keys from the original array
missingKeys :: Json -> Data -> [Json]
missingKeys keys vars = [key | key <- getKeys keys, isNothing $ indexWithJson key vars]
where
-- The keys used for our search
getKeys :: Json -> [Json]
getKeys (JsonArray (arr@(JsonArray _) : _)) = getKeys arr
getKeys (JsonArray js) = js
getKeys j = [j]