{-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 800 {-# OPTIONS_GHC -Wno-redundant-constraints #-} #endif {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} -- | Module for creating filter conditions -- -- Example as used in nested structure for scan: -- -- > scanCond (hashitem' "a" <.> author' <.> name' ==. "x") 20 module Database.DynamoDB.Filter ( -- * Condition datatype FilterCondition(Not) -- * Logical operators , (&&.), (||.) -- * Equality comparisons , (==.), (/=.), (>=.), (>.), (<=.), (<.) -- * Extended functions , attrExists, attrMissing, beginsWith, contains, setContains, valIn, between , size ) where import Control.Lens ((.~)) import Data.Function ((&)) import Data.Maybe (fromMaybe) import qualified Data.Set as Set import qualified Data.Text as T import qualified Network.AWS.DynamoDB.Types as D import Database.DynamoDB.Internal import Database.DynamoDB.Types -- | Numeric/string range comparison. between :: (Ord typ, InCollection col tbl 'FullPath, DynamoScalar v typ) => Column typ ctyp col -> (typ, typ) -> FilterCondition tbl between col (a, b) = Between (nameGen col) (dScalarEncode a) (dScalarEncode b) -- | a IN (b, c, d); the list may contain up to 100 values. valIn :: (InCollection col tbl 'FullPath, DynamoScalar v typ) => Column typ ctyp col -> [typ] -> FilterCondition tbl valIn col lst = In (nameGen col) (map dScalarEncode lst) -- | Check existence of attribute. attrExists :: (InCollection col tbl 'FullPath) => Column typ 'TypColumn col -> FilterCondition tbl attrExists col = AttrExists (nameGen col) -- | Checks non-existence of an attribute attrMissing :: (InCollection col tbl 'FullPath) => Column typ 'TypColumn col -> FilterCondition tbl attrMissing col = AttrMissing (nameGen col) -- | Comparison for text columns. beginsWith :: (InCollection col tbl 'FullPath, IsText typ) => Column typ 'TypColumn col -> T.Text -> FilterCondition tbl beginsWith col txt = BeginsWith (nameGen col) (dScalarEncode txt) -- | CONTAINS condition for text-like attributes. contains :: (InCollection col tbl 'FullPath, IsText typ) => Column typ 'TypColumn col -> T.Text -> FilterCondition tbl contains col txt = Contains (nameGen col) (dScalarEncode txt) -- | CONTAINS condition for sets. setContains :: (InCollection col tbl 'FullPath, DynamoScalar v a) => Column (Set.Set a) 'TypColumn col -> a -> FilterCondition tbl setContains col txt = Contains (nameGen col) (dScalarEncode txt) -- | Size (i.e. number of bytes) of saved attribute. size :: Column typ 'TypColumn col -> Column Int 'TypSize col size (Column lst) = Size lst dcomp :: (InCollection col tbl 'FullPath, DynamoEncodable typ) => T.Text -> Column typ ctyp col -> typ -> FilterCondition tbl dcomp op col val = Comparison (nameGen col) op encval where -- Ord comparing against nothing doesn't make much sense - failback to NULL encval = fromMaybe (D.attributeValue & D.avNULL .~ Just True) (dEncode val) -- | AND for combining conditions. (&&.) :: FilterCondition t -> FilterCondition t -> FilterCondition t (&&.) = And infixr 3 &&. -- | OR for combining conditions (||.) :: FilterCondition t -> FilterCondition t -> FilterCondition t (||.) = Or infixr 3 ||. -- | Tests for equality. Automatically adjusts query to account for missing attributes. -- -- Note: checks against empty values esentially translate to 'attrMissing'. (==.) :: (InCollection col tbl 'FullPath, DynamoEncodable typ) => Column typ ctyp col -> typ -> FilterCondition tbl (==.) col val = case dEncode val of -- Hack to have '==. Nothing' correctly working Nothing -> AttrMissing (nameGen col) -- Hack for '==. ""' or empty set, list, hashmap to work correctly on non-initialized values Just encval | dIsMissing val -> AttrMissing (nameGen col) ||. Comparison (nameGen col) "=" encval | otherwise -> Comparison (nameGen col) "=" encval infix 4 ==. -- | > a /= b === Not (a == b) (/=.) :: (InCollection col tbl 'FullPath, DynamoEncodable typ) => Column typ ctyp col -> typ -> FilterCondition tbl (/=.) col val = Not (col ==. val) infix 4 /=. (<=.) :: (InCollection col tbl 'FullPath, DynamoEncodable typ, Ord typ) => Column typ ctyp col -> typ -> FilterCondition tbl (<=.) = dcomp "<=" infix 4 <=. (<.) :: (InCollection col tbl 'FullPath, DynamoEncodable typ, Ord typ) => Column typ ctyp col -> typ -> FilterCondition tbl (<.) = dcomp "<" infix 4 <. (>.) :: (InCollection col tbl 'FullPath, DynamoEncodable typ, Ord typ) => Column typ ctyp col -> typ -> FilterCondition tbl (>.) = dcomp ">" infix 4 >. (>=.) :: (InCollection col tbl 'FullPath, DynamoEncodable typ, Ord typ) => Column typ ctyp col -> typ -> FilterCondition tbl (>=.) = dcomp ">=" infix 4 >=.