{-# 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.DynamoDB.BatchGetItem
-- 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 BatchGetItem operation returns the attributes of one or more items from
-- one or more tables. You identify requested items by primary key. A single
-- operation can retrieve up to 16 MB of data, which can contain as many as
-- 100 items. BatchGetItem will return a partial result if the response size
-- limit is exceeded, the table's provisioned throughput is exceeded, or an
-- internal processing failure occurs. If a partial result is returned, the
-- operation returns a value for UnprocessedKeys. You can use this value to
-- retry the operation starting with the next item to get. For example, if you
-- ask to retrieve 100 items, but each individual item is 300 KB in size, the
-- system returns 52 items (so as not to exceed the 16 MB limit). It also
-- returns an appropriate UnprocessedKeys value so you can get the next page
-- of results. If desired, your application can include its own logic to
-- assemble the pages of results into one data set. If none of the items can
-- be processed due to insufficient provisioned throughput on all of the
-- tables in the request, then BatchGetItem will return a
-- ProvisionedThroughputExceededException. If at least one of the items is
-- successfully processed, then BatchGetItem completes successfully, while
-- returning the keys of the unread items in UnprocessedKeys. If DynamoDB
-- returns any unprocessed items, you should retry the batch operation on
-- those items. However, we strongly recommend that you use an exponential
-- backoff algorithm. If you retry the batch operation immediately, the
-- underlying read or write requests can still fail due to throttling on the
-- individual tables. If you delay the batch operation using exponential
-- backoff, the individual requests in the batch are much more likely to
-- succeed. For more information, go to Batch Operations and Error Handling in
-- the Amazon DynamoDB Developer Guide. By default, BatchGetItem performs
-- eventually consistent reads on every table in the request. If you want
-- strongly consistent reads instead, you can set ConsistentRead to true for
-- any or all tables. In order to minimize response latency, BatchGetItem
-- retrieves items in parallel. When designing your application, keep in mind
-- that DynamoDB does not return attributes in any particular order. To help
-- parse the response by item, include the primary key values for the items in
-- your request in the AttributesToGet parameter. If a requested item does not
-- exist, it is not returned in the result. Requests for nonexistent items
-- consume the minimum read capacity units according to the type of read. For
-- more information, see Capacity Units Calculations in the Amazon DynamoDB
-- Developer Guide.
--
-- <http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html>
module Network.AWS.DynamoDB.BatchGetItem
    (
    -- * Request
      BatchGetItem
    -- ** Request constructor
    , batchGetItem
    -- ** Request lenses
    , bgiRequestItems
    , bgiReturnConsumedCapacity

    -- * Response
    , BatchGetItemResponse
    -- ** Response constructor
    , batchGetItemResponse
    -- ** Response lenses
    , bgirConsumedCapacity
    , bgirResponses
    , bgirUnprocessedKeys
    ) where

import Network.AWS.Prelude
import Network.AWS.Request.JSON
import Network.AWS.DynamoDB.Types
import qualified GHC.Exts

data BatchGetItem = BatchGetItem
    { _bgiRequestItems           :: Map Text KeysAndAttributes
    , _bgiReturnConsumedCapacity :: Maybe ReturnConsumedCapacity
    } deriving (Eq, Show)

-- | 'BatchGetItem' constructor.
--
-- The fields accessible through corresponding lenses are:
--
-- * 'bgiRequestItems' @::@ 'HashMap' 'Text' 'KeysAndAttributes'
--
-- * 'bgiReturnConsumedCapacity' @::@ 'Maybe' 'ReturnConsumedCapacity'
--
batchGetItem :: BatchGetItem
batchGetItem = BatchGetItem
    { _bgiRequestItems           = mempty
    , _bgiReturnConsumedCapacity = Nothing
    }

-- | A map of one or more table names and, for each table, the corresponding
-- primary keys for the items to retrieve. Each table name can be invoked
-- only once. Each element in the map consists of the following: Keys - An
-- array of primary key attribute values that define specific items in the
-- table. For each primary key, you must provide all of the key attributes.
-- For example, with a hash type primary key, you only need to specify the
-- hash attribute. For a hash-and-range type primary key, you must specify
-- both the hash attribute and the range attribute. AttributesToGet - One or
-- more attributes to be retrieved from the table. By default, all
-- attributes are returned. If a specified attribute is not found, it does
-- not appear in the result. Note that AttributesToGet has no effect on
-- provisioned throughput consumption. DynamoDB determines capacity units
-- consumed based on item size, not on the amount of data that is returned
-- to an application. ConsistentRead - If true, a strongly consistent read
-- is used; if false (the default), an eventually consistent read is used.
bgiRequestItems :: Lens' BatchGetItem (HashMap Text KeysAndAttributes)
bgiRequestItems = lens _bgiRequestItems (\s a -> s { _bgiRequestItems = a }) . _Map

bgiReturnConsumedCapacity :: Lens' BatchGetItem (Maybe ReturnConsumedCapacity)
bgiReturnConsumedCapacity =
    lens _bgiReturnConsumedCapacity
        (\s a -> s { _bgiReturnConsumedCapacity = a })

data BatchGetItemResponse = BatchGetItemResponse
    { _bgirConsumedCapacity :: List "ConsumedCapacity" ConsumedCapacity
    , _bgirResponses        :: Map Text (List "Items" (Map Text AttributeValue))
    , _bgirUnprocessedKeys  :: Map Text KeysAndAttributes
    } deriving (Eq, Show)

-- | 'BatchGetItemResponse' constructor.
--
-- The fields accessible through corresponding lenses are:
--
-- * 'bgirConsumedCapacity' @::@ ['ConsumedCapacity']
--
-- * 'bgirResponses' @::@ 'HashMap' 'Text' ['HashMap' 'Text' 'AttributeValue']
--
-- * 'bgirUnprocessedKeys' @::@ 'HashMap' 'Text' 'KeysAndAttributes'
--
batchGetItemResponse :: BatchGetItemResponse
batchGetItemResponse = BatchGetItemResponse
    { _bgirResponses        = mempty
    , _bgirUnprocessedKeys  = mempty
    , _bgirConsumedCapacity = mempty
    }

-- | The write capacity units consumed by the operation. Each element consists
-- of: TableName - The table that consumed the provisioned throughput.
-- CapacityUnits - The total number of capacity units consumed.
bgirConsumedCapacity :: Lens' BatchGetItemResponse [ConsumedCapacity]
bgirConsumedCapacity =
    lens _bgirConsumedCapacity (\s a -> s { _bgirConsumedCapacity = a })
        . _List

-- | A map of table name to a list of items. Each object in Responses consists
-- of a table name, along with a map of attribute data consisting of the
-- data type and attribute value.
bgirResponses :: Lens' BatchGetItemResponse (HashMap Text [HashMap Text AttributeValue])
bgirResponses = lens _bgirResponses (\s a -> s { _bgirResponses = a }) . _Map

-- | A map of tables and their respective keys that were not processed with
-- the current response. The UnprocessedKeys value is in the same form as
-- RequestItems, so the value can be provided directly to a subsequent
-- BatchGetItem operation. For more information, see RequestItems in the
-- Request Parameters section. Each element consists of: Keys - An array of
-- primary key attribute values that define specific items in the table.
-- AttributesToGet - One or more attributes to be retrieved from the table
-- or index. By default, all attributes are returned. If a specified
-- attribute is not found, it does not appear in the result. ConsistentRead
-- - The consistency of a read operation. If set to true, then a strongly
-- consistent read is used; otherwise, an eventually consistent read is
-- used. If there are no unprocessed keys remaining, the response contains
-- an empty UnprocessedKeys map.
bgirUnprocessedKeys :: Lens' BatchGetItemResponse (HashMap Text KeysAndAttributes)
bgirUnprocessedKeys =
    lens _bgirUnprocessedKeys (\s a -> s { _bgirUnprocessedKeys = a })
        . _Map

instance ToPath BatchGetItem where
    toPath = const "/"

instance ToQuery BatchGetItem where
    toQuery = const mempty

instance ToHeaders BatchGetItem

instance ToJSON BatchGetItem where
    toJSON BatchGetItem{..} = object
        [ "RequestItems"           .= _bgiRequestItems
        , "ReturnConsumedCapacity" .= _bgiReturnConsumedCapacity
        ]

instance AWSRequest BatchGetItem where
    type Sv BatchGetItem = DynamoDB
    type Rs BatchGetItem = BatchGetItemResponse

    request  = post "BatchGetItem"
    response = jsonResponse

instance FromJSON BatchGetItemResponse where
    parseJSON = withObject "BatchGetItemResponse" $ \o -> BatchGetItemResponse
        <$> o .:  "ConsumedCapacity"
        <*> o .:  "Responses"
        <*> o .:  "UnprocessedKeys"