{-# LANGUAGE DataKinds                   #-}
{-# LANGUAGE DeriveGeneric               #-}
{-# LANGUAGE FlexibleInstances           #-}
{-# LANGUAGE GeneralizedNewtypeDeriving  #-}
{-# LANGUAGE LambdaCase                  #-}
{-# LANGUAGE NoImplicitPrelude           #-}
{-# LANGUAGE OverloadedStrings           #-}
{-# LANGUAGE RecordWildCards             #-}
{-# LANGUAGE TypeFamilies                #-}

{-# OPTIONS_GHC -fno-warn-unused-imports #-}

-- Module      : Network.AWS.SDB.Select
-- Copyright   : (c) 2013-2014 Brendan Hay <brendan.g.hay@gmail.com>
-- License     : This Source Code Form is subject to the terms of
--               the Mozilla Public License, v. 2.0.
--               A copy of the MPL can be found in the LICENSE file or
--               you can obtain it at http://mozilla.org/MPL/2.0/.
-- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>
-- Stability   : experimental
-- Portability : non-portable (GHC extensions)

-- | The Select operation returns a set of attributes for ItemNames that match
-- the select expression. Select is similar to the standard SQL SELECT
-- statement. The total size of the response cannot exceed 1 MB in total size.
-- Amazon SimpleDB automatically adjusts the number of items returned per page
-- to enforce this limit. For example, if the client asks to retrieve 2500
-- items, but each individual item is 10 kB in size, the system returns 100
-- items and an appropriate NextToken so the client can access the next page
-- of results. For information on how to construct select expressions, see
-- Using Select to Create Amazon SimpleDB Queries in the Developer Guide.
--
-- <http://docs.aws.amazon.com/AmazonSimpleDB/latest/DeveloperGuide/SDB_API_Select.html>
module Network.AWS.SDB.Select
    (
    -- * Request
      Select
    -- ** Request constructor
    , select
    -- ** Request lenses
    , sConsistentRead
    , sNextToken
    , sSelectExpression

    -- * Response
    , SelectResponse
    -- ** Response constructor
    , selectResponse
    -- ** Response lenses
    , srItems
    , srNextToken
    ) where

import Network.AWS.Prelude
import Network.AWS.Request.Query
import Network.AWS.SDB.Types
import qualified GHC.Exts

data Select = Select
    { _sConsistentRead   :: Maybe Bool
    , _sNextToken        :: Maybe Text
    , _sSelectExpression :: Text
    } deriving (Eq, Ord, Show)

-- | 'Select' constructor.
--
-- The fields accessible through corresponding lenses are:
--
-- * 'sConsistentRead' @::@ 'Maybe' 'Bool'
--
-- * 'sNextToken' @::@ 'Maybe' 'Text'
--
-- * 'sSelectExpression' @::@ 'Text'
--
select :: Text -- ^ 'sSelectExpression'
       -> Select
select p1 = Select
    { _sSelectExpression = p1
    , _sNextToken        = Nothing
    , _sConsistentRead   = Nothing
    }

-- | Determines whether or not strong consistency should be enforced when data
-- is read from SimpleDB. If true, any data previously written to SimpleDB
-- will be returned. Otherwise, results will be consistent eventually, and
-- the client may not see data that was written immediately before your
-- read.
sConsistentRead :: Lens' Select (Maybe Bool)
sConsistentRead = lens _sConsistentRead (\s a -> s { _sConsistentRead = a })

-- | A string informing Amazon SimpleDB where to start the next list of
-- ItemNames.
sNextToken :: Lens' Select (Maybe Text)
sNextToken = lens _sNextToken (\s a -> s { _sNextToken = a })

-- | The expression used to query the domain.
sSelectExpression :: Lens' Select Text
sSelectExpression =
    lens _sSelectExpression (\s a -> s { _sSelectExpression = a })

data SelectResponse = SelectResponse
    { _srItems     :: List "Item" Item
    , _srNextToken :: Maybe Text
    } deriving (Eq, Show)

-- | 'SelectResponse' constructor.
--
-- The fields accessible through corresponding lenses are:
--
-- * 'srItems' @::@ ['Item']
--
-- * 'srNextToken' @::@ 'Maybe' 'Text'
--
selectResponse :: [Item] -- ^ 'srItems'
               -> SelectResponse
selectResponse p1 = SelectResponse
    { _srItems     = withIso _List (const id) p1
    , _srNextToken = Nothing
    }

-- | A list of items that match the select expression.
srItems :: Lens' SelectResponse [Item]
srItems = lens _srItems (\s a -> s { _srItems = a }) . _List

-- | An opaque token indicating that more items than MaxNumberOfItems were
-- matched, the response size exceeded 1 megabyte, or the execution time
-- exceeded 5 seconds.
srNextToken :: Lens' SelectResponse (Maybe Text)
srNextToken = lens _srNextToken (\s a -> s { _srNextToken = a })

instance ToPath Select where
    toPath = const "/"

instance ToQuery Select where
    toQuery Select{..} = mconcat
        [ "ConsistentRead"   =? _sConsistentRead
        , "NextToken"        =? _sNextToken
        , "SelectExpression" =? _sSelectExpression
        ]

instance ToHeaders Select

instance AWSRequest Select where
    type Sv Select = SDB
    type Rs Select = SelectResponse

    request  = post "Select"
    response = xmlResponse

instance FromXML SelectResponse where
    parseXML = withElement "SelectResult" $ \x -> SelectResponse
        <$> parseXML x
        <*> x .@? "NextToken"

instance AWSPager Select where
    page rq rs
        | stop (rq ^. sNextToken) = Nothing
        | otherwise = (\x -> rq & sNextToken ?~ x)
            <$> (rs ^. srNextToken)