module LaunchDarkly.Server.Integrations.TestData.FlagBuilder
    ( FlagBuilder(..)
    , UserKey
    , VariationIndex
    , newFlagBuilder
    , booleanFlag
    , on
    , fallthroughVariation
    , offVariation
    , variationForAllUsers
    , valueForAllUsers
    , variationForUser
    , variations
    , buildFlag
    , UserAttribute
    , ifMatch
    , ifNotMatch
    , FlagRuleBuilder
    , andMatch
    , andNotMatch
    , thenReturn
    , Variation
    )
    where

import qualified Data.Aeson as Aeson
import           Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import           Data.Text (Text)
import qualified Data.Text as T
import           GHC.Natural (Natural)
import qualified LaunchDarkly.Server.Features as F
import qualified LaunchDarkly.Server.Operators as Op
import           Data.Function ((&))

type UserKey = Text
type VariationIndex = Integer

trueVariationForBoolean, falseVariationForBoolean :: VariationIndex
trueVariationForBoolean :: Integer
trueVariationForBoolean = Integer
0
falseVariationForBoolean :: Integer
falseVariationForBoolean = Integer
1

variationForBoolean :: Bool -> VariationIndex
variationForBoolean :: Bool -> Integer
variationForBoolean Bool
True = Integer
trueVariationForBoolean
variationForBoolean Bool
False = Integer
falseVariationForBoolean

-- |
-- A builder for feature flag configurations to be used with "LaunchDarkly.Server.Integrations.TestData".
-- 
-- see 'LaunchDarkly.Server.Integrations.TestData.flag' and
-- 'LaunchDarkly.Server.Integrations.TestData.update'
data FlagBuilder = FlagBuilder
    { FlagBuilder -> UserKey
fbKey :: Text
    , FlagBuilder -> Maybe Integer
fbOffVariation :: Maybe VariationIndex
    , FlagBuilder -> Bool
fbOn :: Bool
    , FlagBuilder -> Maybe Integer
fbFallthroughVariation :: Maybe VariationIndex
    , FlagBuilder -> [Value]
fbVariations :: [Aeson.Value]
    , FlagBuilder -> Map UserKey Integer
fbTargetMap :: Map UserKey VariationIndex
    , FlagBuilder -> [FlagRule]
fbRules :: [FlagRule]
    } deriving (Int -> FlagBuilder -> ShowS
[FlagBuilder] -> ShowS
FlagBuilder -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FlagBuilder] -> ShowS
$cshowList :: [FlagBuilder] -> ShowS
show :: FlagBuilder -> String
$cshow :: FlagBuilder -> String
showsPrec :: Int -> FlagBuilder -> ShowS
$cshowsPrec :: Int -> FlagBuilder -> ShowS
Show)

fbTargets :: FlagBuilder -> [F.Target]
fbTargets :: FlagBuilder -> [Target]
fbTargets FlagBuilder
flagBuilder =
    forall k a. Map k a -> [a]
Map.elems forall a b. (a -> b) -> a -> b
$
    forall k a b. (k -> a -> b) -> Map k a -> Map k b
Map.mapWithKey (forall a b c. (a -> b -> c) -> b -> a -> c
flip [UserKey] -> Integer -> Target
F.Target) forall a b. (a -> b) -> a -> b
$
    forall k a b. (k -> a -> b -> b) -> b -> Map k a -> b
Map.foldrWithKey forall {k} {a}. Ord k => a -> k -> Map k [a] -> Map k [a]
go forall a. Monoid a => a
mempty (FlagBuilder -> Map UserKey Integer
fbTargetMap FlagBuilder
flagBuilder)
  where
    go :: a -> k -> Map k [a] -> Map k [a]
go a
userKey k
variation =
        forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
Map.insertWith forall a. Semigroup a => a -> a -> a
(<>) k
variation [a
userKey]

buildFlag :: Natural -> FlagBuilder -> F.Flag
buildFlag :: Natural -> FlagBuilder -> Flag
buildFlag Natural
version FlagBuilder
flagBuilder =
    F.Flag
        { $sel:key:Flag :: UserKey
F.key = FlagBuilder -> UserKey
fbKey FlagBuilder
flagBuilder
        , $sel:version:Flag :: Natural
F.version = Natural
version
        , $sel:on:Flag :: Bool
F.on = FlagBuilder -> Bool
fbOn FlagBuilder
flagBuilder
        , $sel:trackEvents:Flag :: Bool
F.trackEvents = Bool
False
        , $sel:trackEventsFallthrough:Flag :: Bool
F.trackEventsFallthrough = Bool
False
        , $sel:deleted:Flag :: Bool
F.deleted = Bool
False
        , $sel:prerequisites:Flag :: [Prerequisite]
F.prerequisites = []
        , $sel:salt:Flag :: UserKey
F.salt = UserKey
"salt"
        , $sel:targets:Flag :: [Target]
F.targets = FlagBuilder -> [Target]
fbTargets FlagBuilder
flagBuilder
        , $sel:rules:Flag :: [Rule]
F.rules = forall num a b. Integral num => (num -> a -> b) -> [a] -> [b]
mapWithIndex Integer -> FlagRule -> Rule
convertFlagRule (FlagBuilder -> [FlagRule]
fbRules FlagBuilder
flagBuilder)
        , $sel:fallthrough:Flag :: VariationOrRollout
F.fallthrough = Maybe Integer -> Maybe Rollout -> VariationOrRollout
F.VariationOrRollout (FlagBuilder -> Maybe Integer
fbFallthroughVariation FlagBuilder
flagBuilder) forall a. Maybe a
Nothing
        , $sel:offVariation:Flag :: Maybe Integer
F.offVariation = FlagBuilder -> Maybe Integer
fbOffVariation FlagBuilder
flagBuilder
        , $sel:variations:Flag :: [Value]
F.variations = FlagBuilder -> [Value]
fbVariations FlagBuilder
flagBuilder
        , $sel:debugEventsUntilDate:Flag :: Maybe Natural
F.debugEventsUntilDate = forall a. Maybe a
Nothing
        , $sel:clientSideAvailability:Flag :: ClientSideAvailability
F.clientSideAvailability = Bool -> Bool -> Bool -> ClientSideAvailability
F.ClientSideAvailability Bool
False Bool
False Bool
False
        }

mapWithIndex :: Integral num => (num -> a -> b) -> [a] -> [b]
mapWithIndex :: forall num a b. Integral num => (num -> a -> b) -> [a] -> [b]
mapWithIndex num -> a -> b
f [a]
l =
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry num -> a -> b
f) (forall a b. [a] -> [b] -> [(a, b)]
zip [num
0..] [a]
l)

newFlagBuilder :: Text -> FlagBuilder
newFlagBuilder :: UserKey -> FlagBuilder
newFlagBuilder UserKey
key =
    FlagBuilder
        { $sel:fbKey:FlagBuilder :: UserKey
fbKey = UserKey
key
        , $sel:fbOffVariation:FlagBuilder :: Maybe Integer
fbOffVariation = forall a. Maybe a
Nothing
        , $sel:fbOn:FlagBuilder :: Bool
fbOn = Bool
True
        , $sel:fbFallthroughVariation:FlagBuilder :: Maybe Integer
fbFallthroughVariation = forall a. Maybe a
Nothing
        , $sel:fbVariations:FlagBuilder :: [Value]
fbVariations = forall a. Monoid a => a
mempty
        , $sel:fbTargetMap:FlagBuilder :: Map UserKey Integer
fbTargetMap = forall a. Monoid a => a
mempty
        , $sel:fbRules:FlagBuilder :: [FlagRule]
fbRules = forall a. Monoid a => a
mempty
        }

booleanFlagVariations :: [Aeson.Value]
booleanFlagVariations :: [Value]
booleanFlagVariations = [Bool -> Value
Aeson.Bool Bool
True, Bool -> Value
Aeson.Bool Bool
False]

isBooleanFlag :: FlagBuilder -> Bool
isBooleanFlag :: FlagBuilder -> Bool
isBooleanFlag FlagBuilder
flagBuilder
  | [Value]
booleanFlagVariations forall a. Eq a => a -> a -> Bool
== FlagBuilder -> [Value]
fbVariations FlagBuilder
flagBuilder = Bool
True
  | Bool
otherwise = Bool
False

-- | 
-- A shortcut for setting the flag to use the standard boolean configuration.
--
-- This is the default for all new flags created with 'LaunchDarkly.Server.Integrations.TestData.flag'. The flag
-- will have two variations, @True@ and @False@ (in that order); it will return
-- @False@ whenever targeting is off, and @True@ when targeting is on if no other
-- settings specify otherwise.
booleanFlag :: FlagBuilder -> FlagBuilder
booleanFlag :: FlagBuilder -> FlagBuilder
booleanFlag FlagBuilder
flagBuilder
    | FlagBuilder -> Bool
isBooleanFlag FlagBuilder
flagBuilder =
        FlagBuilder
flagBuilder
    | Bool
otherwise =
        FlagBuilder
flagBuilder
            forall a b. a -> (a -> b) -> b
& [Value] -> FlagBuilder -> FlagBuilder
variations [Value]
booleanFlagVariations
            forall a b. a -> (a -> b) -> b
& forall val. Variation val => val -> FlagBuilder -> FlagBuilder
fallthroughVariation Integer
trueVariationForBoolean
            forall a b. a -> (a -> b) -> b
& forall val. Variation val => val -> FlagBuilder -> FlagBuilder
offVariation Integer
falseVariationForBoolean
-- |
-- Sets targeting to be on or off for this flag.
--
-- The effect of this depends on the rest of the flag configuration, just as it does on the
-- real LaunchDarkly dashboard. In the default configuration that you get from calling
-- 'LaunchDarkly.Server.Integrations.TestData.flag' with a new flag key, the flag will return @False@ 
-- whenever targeting is off, and @True@ when targeting is on.
on :: Bool -- ^ isOn @True@ if targeting should be on
   -> FlagBuilder 
   -> FlagBuilder
on :: Bool -> FlagBuilder -> FlagBuilder
on Bool
isOn FlagBuilder
fb =
    FlagBuilder
fb{ $sel:fbOn:FlagBuilder :: Bool
fbOn = Bool
isOn }

-- |
-- Removes any existing rules from the flag. 
-- This undoes the effect of methods like 'ifMatch' or 'ifNotMatch'
clearRules :: FlagBuilder -> FlagBuilder
clearRules :: FlagBuilder -> FlagBuilder
clearRules FlagBuilder
fb =
    FlagBuilder
fb{ $sel:fbRules:FlagBuilder :: [FlagRule]
fbRules = forall a. Monoid a => a
mempty }

-- |
-- Removes any existing user targets from the flag. 
-- This undoes the effect of methods like 'variationForUser'
clearUserTargets :: FlagBuilder -> FlagBuilder
clearUserTargets :: FlagBuilder -> FlagBuilder
clearUserTargets FlagBuilder
fb =
    FlagBuilder
fb{ $sel:fbTargetMap:FlagBuilder :: Map UserKey Integer
fbTargetMap = forall a. Monoid a => a
mempty }

-- |
-- Sets the flag to always return the specified variation value for all users.
--
-- The value may be of any type that implements 'Aeson.ToJSON'. This method changes the
-- flag to have only a single variation, which is this value, and to return the same
-- variation regardless of whether targeting is on or off. Any existing targets or rules
-- are removed.
valueForAllUsers :: Aeson.ToJSON value
                 => value -- the desired value to be returned for all users
                 -> FlagBuilder 
                 -> FlagBuilder
valueForAllUsers :: forall value. ToJSON value => value -> FlagBuilder -> FlagBuilder
valueForAllUsers value
val FlagBuilder
fb =
    FlagBuilder
fb forall a b. a -> (a -> b) -> b
& [Value] -> FlagBuilder -> FlagBuilder
variations [forall a. ToJSON a => a -> Value
Aeson.toJSON value
val]
       forall a b. a -> (a -> b) -> b
& forall val. Variation val => val -> FlagBuilder -> FlagBuilder
variationForAllUsers (Integer
0 :: VariationIndex)

-- |
-- Changes the allowable variation values for the flag.
--
-- The value may be of any JSON type, as defined by 'Aeson.Value'. For instance, a boolean flag
-- normally has [toJSON True, toJSON False]; a string-valued flag might have
-- [toJSON "red", toJSON "green"]; etc.
variations :: [Aeson.Value] -- ^ the desired variations
           -> FlagBuilder 
           -> FlagBuilder
variations :: [Value] -> FlagBuilder -> FlagBuilder
variations [Value]
values FlagBuilder
fb =
    FlagBuilder
fb{ $sel:fbVariations:FlagBuilder :: [Value]
fbVariations = [Value]
values }

-- Should this actually use overloaded function names?
class Variation val where
    -- |
    -- Specifies the fallthrough variation. The fallthrough is the value
    -- that is returned if targeting is on and the user was not matched by a more specific
    -- target or rule.
    --
    -- If the flag was previously configured with other variations and the variation specified is a boolean,
    -- this also changes it to a boolean flag.
    fallthroughVariation :: val -- ^ @True@ or @False@ or the desired fallthrough variation index: 0 for the first, 1 for the second, etc.
                         -> FlagBuilder 
                         -> FlagBuilder

    -- | 
    -- Specifies the off variation for a flag. This is the variation that is returned
    -- whenever targeting is off.
    --
    -- If the flag was previously configured with other variations and the variation specified is a boolean,
    -- this also changes it to a boolean flag.
    offVariation :: val -- ^ @True@ or @False@ or the desired fallthrough variation index: 0 for the first, 1 for the second, etc.
                 -> FlagBuilder 
                 -> FlagBuilder

    -- |
    -- Sets the flag to always return the specified variation for all users.
    --
    -- The variation is specified, Targeting is switched on, and any existing targets or rules are removed.
    -- The fallthrough variation is set to the specified value. The off variation is left unchanged.
    --
    -- If the flag was previously configured with other variations and the variation specified is a boolean,
    -- this also changes it to a boolean flag.
    variationForAllUsers :: val -- ^ @True@ or @False@ or the desired fallthrough variation index: 0 for the first, 1 for the second, etc.
                         -> FlagBuilder 
                         -> FlagBuilder

    -- |
    -- Sets the flag to return the specified variation for a specific user key when targeting
    -- is on.
    --
    -- This has no effect when targeting is turned off for the flag.
    --
    -- If the flag was previously configured with other variations and the variation specified is a boolean,
    -- this also changes it to a boolean flag.
    variationForUser :: UserKey -- ^ a user key to target
                     -> val -- ^ @True@ or @False@ or the desired fallthrough variation index: 0 for the first, 1 for the second, etc.
                     -> FlagBuilder 
                     -> FlagBuilder
    
    -- |
    -- Finishes defining the rule, specifying the result as either a boolean
    -- or a variation index.
    -- 
    -- If the flag was previously configured with other variations and the variation specified is a boolean,
    -- this also changes it to a boolean flag.
    thenReturn :: val -- ^ @True@ or @False@ or the desired fallthrough variation index: 0 for the first, 1 for the second, etc.
               -> FlagRuleBuilder 
               -> FlagBuilder

instance Variation Integer where
    fallthroughVariation :: Integer -> FlagBuilder -> FlagBuilder
fallthroughVariation Integer
variationIndex FlagBuilder
fb =
        FlagBuilder
fb{ $sel:fbFallthroughVariation:FlagBuilder :: Maybe Integer
fbFallthroughVariation = forall a. a -> Maybe a
Just Integer
variationIndex }

    offVariation :: Integer -> FlagBuilder -> FlagBuilder
offVariation Integer
variationIndex FlagBuilder
fb =
        FlagBuilder
fb{ $sel:fbOffVariation:FlagBuilder :: Maybe Integer
fbOffVariation = forall a. a -> Maybe a
Just Integer
variationIndex }

    variationForAllUsers :: Integer -> FlagBuilder -> FlagBuilder
variationForAllUsers Integer
variationIndex FlagBuilder
fb =
        FlagBuilder
fb forall a b. a -> (a -> b) -> b
& Bool -> FlagBuilder -> FlagBuilder
on Bool
True
           forall a b. a -> (a -> b) -> b
& FlagBuilder -> FlagBuilder
clearRules
           forall a b. a -> (a -> b) -> b
& FlagBuilder -> FlagBuilder
clearUserTargets
           forall a b. a -> (a -> b) -> b
& forall val. Variation val => val -> FlagBuilder -> FlagBuilder
fallthroughVariation Integer
variationIndex

    variationForUser :: UserKey -> Integer -> FlagBuilder -> FlagBuilder
variationForUser UserKey
userKey Integer
variationIndex FlagBuilder
fb =
        FlagBuilder
fb{ $sel:fbTargetMap:FlagBuilder :: Map UserKey Integer
fbTargetMap = forall k a. Ord k => k -> a -> Map k a -> Map k a
Map.insert UserKey
userKey Integer
variationIndex (FlagBuilder -> Map UserKey Integer
fbTargetMap FlagBuilder
fb) }

    thenReturn :: Integer -> FlagRuleBuilder -> FlagBuilder
thenReturn Integer
variationIndex FlagRuleBuilder
ruleBuilder =
        let fb :: FlagBuilder
fb = FlagRuleBuilder -> FlagBuilder
frbBaseBuilder FlagRuleBuilder
ruleBuilder
        in FlagBuilder
fb{ $sel:fbRules:FlagBuilder :: [FlagRule]
fbRules = [Clause] -> Integer -> FlagRule
FlagRule (FlagRuleBuilder -> [Clause]
frbClauses FlagRuleBuilder
ruleBuilder) Integer
variationIndex forall a. a -> [a] -> [a]
: FlagBuilder -> [FlagRule]
fbRules FlagBuilder
fb }

instance Variation Bool where
    fallthroughVariation :: Bool -> FlagBuilder -> FlagBuilder
fallthroughVariation Bool
value FlagBuilder
fb =
        FlagBuilder
fb forall a b. a -> (a -> b) -> b
& FlagBuilder -> FlagBuilder
booleanFlag
           forall a b. a -> (a -> b) -> b
& forall val. Variation val => val -> FlagBuilder -> FlagBuilder
fallthroughVariation (Bool -> Integer
variationForBoolean Bool
value)
    offVariation :: Bool -> FlagBuilder -> FlagBuilder
offVariation Bool
value FlagBuilder
fb =
        FlagBuilder
fb forall a b. a -> (a -> b) -> b
& FlagBuilder -> FlagBuilder
booleanFlag
           forall a b. a -> (a -> b) -> b
& forall val. Variation val => val -> FlagBuilder -> FlagBuilder
offVariation (Bool -> Integer
variationForBoolean Bool
value)
    variationForAllUsers :: Bool -> FlagBuilder -> FlagBuilder
variationForAllUsers Bool
value FlagBuilder
fb =
        FlagBuilder
fb forall a b. a -> (a -> b) -> b
& FlagBuilder -> FlagBuilder
booleanFlag
           forall a b. a -> (a -> b) -> b
& forall val. Variation val => val -> FlagBuilder -> FlagBuilder
variationForAllUsers (Bool -> Integer
variationForBoolean Bool
value)
    variationForUser :: UserKey -> Bool -> FlagBuilder -> FlagBuilder
variationForUser UserKey
userKey Bool
value FlagBuilder
fb =
        FlagBuilder
fb forall a b. a -> (a -> b) -> b
& FlagBuilder -> FlagBuilder
booleanFlag
           forall a b. a -> (a -> b) -> b
& forall val.
Variation val =>
UserKey -> val -> FlagBuilder -> FlagBuilder
variationForUser UserKey
userKey (Bool -> Integer
variationForBoolean Bool
value)
    thenReturn :: Bool -> FlagRuleBuilder -> FlagBuilder
thenReturn Bool
value FlagRuleBuilder
ruleBuilder =
        FlagRuleBuilder
ruleBuilder { $sel:frbBaseBuilder:FlagRuleBuilder :: FlagBuilder
frbBaseBuilder = FlagBuilder -> FlagBuilder
booleanFlag forall a b. (a -> b) -> a -> b
$ FlagRuleBuilder -> FlagBuilder
frbBaseBuilder FlagRuleBuilder
ruleBuilder }
            forall a b. a -> (a -> b) -> b
& forall val. Variation val => val -> FlagRuleBuilder -> FlagBuilder
thenReturn (Bool -> Integer
variationForBoolean Bool
value)

type UserAttribute = Text

-- |
-- Starts defining a flag rule, using the "is one of" operator.
--
-- For example, this creates a rule that returns @True@ if the name is \"Patsy\" or \"Edina\":
-- 
-- @
-- testData
--     & flag "flag"
--     & ifMatch "name" [toJSON \"Patsy\", toJSON \"Edina\"]
--     & thenReturn True
-- @
ifMatch :: UserAttribute -- ^ attribute the user attribute to match against
        -> [Aeson.Value] -- ^ values to compare to
        -> FlagBuilder 
        -> FlagRuleBuilder -- ^ call 'thenReturn' to finish the rule, or add more tests with 'andMatch' or 'andNotMatch' 
ifMatch :: UserKey -> [Value] -> FlagBuilder -> FlagRuleBuilder
ifMatch UserKey
userAttribute [Value]
values FlagBuilder
fb =
    FlagBuilder -> FlagRuleBuilder
newFlagRuleBuilder FlagBuilder
fb
     forall a b. a -> (a -> b) -> b
& UserKey -> [Value] -> FlagRuleBuilder -> FlagRuleBuilder
andMatch UserKey
userAttribute [Value]
values

-- |
-- Starts defining a flag rule, using the "is not one of" operator.
--
-- For example, this creates a rule that returns @True@ if the name is neither \"Saffron\" nor \"Bubble\"
-- 
-- @
-- testData
--     & flag "flag"
--     & ifNotMatch "name" [toJSON \"Saffron\", toJSON \"Bubble\"]
--     & thenReturn True
-- @
ifNotMatch :: UserAttribute -- ^ attribute the user attribute to match against
           -> [Aeson.Value] -- ^ values to compare to
           -> FlagBuilder 
           -> FlagRuleBuilder -- ^ call 'thenReturn' to finish the rule, or add more tests with 'andMatch' or 'andNotMatch' 
ifNotMatch :: UserKey -> [Value] -> FlagBuilder -> FlagRuleBuilder
ifNotMatch UserKey
userAttribute [Value]
values FlagBuilder
fb =
    FlagBuilder -> FlagRuleBuilder
newFlagRuleBuilder FlagBuilder
fb
     forall a b. a -> (a -> b) -> b
& UserKey -> [Value] -> FlagRuleBuilder -> FlagRuleBuilder
andNotMatch UserKey
userAttribute [Value]
values

data Clause = Clause
    { Clause -> UserKey
clauseAttribute :: UserAttribute
    , Clause -> [Value]
clauseValues    :: [Aeson.Value]
    , Clause -> Bool
clauseNegate    :: Bool
    } deriving (Int -> Clause -> ShowS
[Clause] -> ShowS
Clause -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Clause] -> ShowS
$cshowList :: [Clause] -> ShowS
show :: Clause -> String
$cshow :: Clause -> String
showsPrec :: Int -> Clause -> ShowS
$cshowsPrec :: Int -> Clause -> ShowS
Show)

data FlagRule = FlagRule
    { FlagRule -> [Clause]
frClauses :: [Clause]
    , FlagRule -> Integer
frVariation :: VariationIndex
    } deriving (Int -> FlagRule -> ShowS
[FlagRule] -> ShowS
FlagRule -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FlagRule] -> ShowS
$cshowList :: [FlagRule] -> ShowS
show :: FlagRule -> String
$cshow :: FlagRule -> String
showsPrec :: Int -> FlagRule -> ShowS
$cshowsPrec :: Int -> FlagRule -> ShowS
Show)

convertFlagRule :: Integer -> FlagRule -> F.Rule
convertFlagRule :: Integer -> FlagRule -> Rule
convertFlagRule Integer
idx FlagRule
flagRule =
    F.Rule
        { $sel:id:Rule :: UserKey
F.id = String -> UserKey
T.pack forall a b. (a -> b) -> a -> b
$ String
"rule" forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show Integer
idx
        , $sel:variationOrRollout:Rule :: VariationOrRollout
F.variationOrRollout = Maybe Integer -> Maybe Rollout -> VariationOrRollout
F.VariationOrRollout (forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ FlagRule -> Integer
frVariation FlagRule
flagRule) forall a. Maybe a
Nothing
        , $sel:clauses:Rule :: [Clause]
F.clauses = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Clause -> Clause
convertClause (FlagRule -> [Clause]
frClauses FlagRule
flagRule)
        , $sel:trackEvents:Rule :: Bool
F.trackEvents = Bool
False
        }

convertClause :: Clause -> F.Clause
convertClause :: Clause -> Clause
convertClause Clause
clause =
    F.Clause
        { $sel:attribute:Clause :: UserKey
F.attribute = Clause -> UserKey
clauseAttribute Clause
clause
        , $sel:negate:Clause :: Bool
F.negate = Clause -> Bool
clauseNegate Clause
clause
        , $sel:values:Clause :: [Value]
F.values = Clause -> [Value]
clauseValues Clause
clause
        , $sel:op:Clause :: Op
F.op = Op
Op.OpIn
        }
-- |
-- A builder for feature flag rules to be used with 'FlagBuilder'.
--
-- In the LaunchDarkly model, a flag can have any number of rules, and a rule can have any number of
-- clauses. A clause is an individual test such as \"name is \'X\'\". A rule matches a user if all of the
-- rule's clauses match the user.
--
-- To start defining a rule, use one of the matching functions such as 'ifMatch' or 'ifNotMatch'. 
-- This defines the first clause for the rule.
-- Optionally, you may add more clauses with the rule builder functions such as 'andMatch' and 'andNotMatch'. 
-- Finally, call 'thenReturn' to finish defining the rule.
data FlagRuleBuilder = FlagRuleBuilder
    { FlagRuleBuilder -> [Clause]
frbClauses :: [Clause]
    , FlagRuleBuilder -> FlagBuilder
frbBaseBuilder :: FlagBuilder
    } deriving (Int -> FlagRuleBuilder -> ShowS
[FlagRuleBuilder] -> ShowS
FlagRuleBuilder -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FlagRuleBuilder] -> ShowS
$cshowList :: [FlagRuleBuilder] -> ShowS
show :: FlagRuleBuilder -> String
$cshow :: FlagRuleBuilder -> String
showsPrec :: Int -> FlagRuleBuilder -> ShowS
$cshowsPrec :: Int -> FlagRuleBuilder -> ShowS
Show)

newFlagRuleBuilder :: FlagBuilder -> FlagRuleBuilder
newFlagRuleBuilder :: FlagBuilder -> FlagRuleBuilder
newFlagRuleBuilder FlagBuilder
baseBuilder =
    FlagRuleBuilder
        { $sel:frbClauses:FlagRuleBuilder :: [Clause]
frbClauses = forall a. Monoid a => a
mempty
        , $sel:frbBaseBuilder:FlagRuleBuilder :: FlagBuilder
frbBaseBuilder = FlagBuilder
baseBuilder
        }
-- |
-- Adds another clause, using the "is one of" operator.
--
-- For example, this creates a rule that returns @True@ if the name is \"Patsy\" and the
-- country is \"gb\":
-- 
-- @
-- testData 
--     & flag "flag"
--     & ifMatch "name" [toJSON \"Patsy\"]
--     & andMatch "country" [toJSON \"gb\"]
--     & thenReturn True
-- @ 
andMatch :: UserAttribute -- ^ the user attribute to match against
         -> [Aeson.Value] -- ^ values to compare to
         -> FlagRuleBuilder 
         -> FlagRuleBuilder
andMatch :: UserKey -> [Value] -> FlagRuleBuilder -> FlagRuleBuilder
andMatch UserKey
userAttribute [Value]
values FlagRuleBuilder
ruleBuilder =
    FlagRuleBuilder
ruleBuilder{ $sel:frbClauses:FlagRuleBuilder :: [Clause]
frbClauses = UserKey -> [Value] -> Bool -> Clause
Clause UserKey
userAttribute [Value]
values Bool
False forall a. a -> [a] -> [a]
: FlagRuleBuilder -> [Clause]
frbClauses FlagRuleBuilder
ruleBuilder }

-- |
-- Adds another clause, using the "is not one of" operator.
--
-- For example, this creates a rule that returns @True@ if the name is \"Patsy\" and the
-- country is not \"gb\":
-- 
-- @
-- testData 
--     & flag "flag"
--     & ifMatch "name" [toJSON \"Patsy\"]
--     & andNotMatch "country" [toJSON \"gb\"]
--     & thenReturn True
-- @ 
andNotMatch :: UserAttribute -- ^ the user attribute to match against
            -> [Aeson.Value] -- ^ values to compare to
            -> FlagRuleBuilder 
            -> FlagRuleBuilder
andNotMatch :: UserKey -> [Value] -> FlagRuleBuilder -> FlagRuleBuilder
andNotMatch UserKey
userAttribute [Value]
values FlagRuleBuilder
ruleBuilder =
    FlagRuleBuilder
ruleBuilder{ $sel:frbClauses:FlagRuleBuilder :: [Clause]
frbClauses = UserKey -> [Value] -> Bool -> Clause
Clause UserKey
userAttribute [Value]
values Bool
True forall a. a -> [a] -> [a]
: FlagRuleBuilder -> [Clause]
frbClauses FlagRuleBuilder
ruleBuilder }