src/Resources/DynamoDbTable.php
protected function addToTransaction(
        $record = null,
        $id = null,
        $extras = null,
        $rollback = false,
        $continue = false,
        $single = false
    ) {
        $ssFilters = array_get($extras, 'ss_filters');
        $fields = array_get($extras, ApiOptions::FIELDS);
        $idFields = array_get($extras, 'id_fields');
        $updates = array_get($extras, 'updates');

        $out = [];
        switch ($this->getAction()) {
            case Verbs::POST:
                $parsed = $this->parseRecord($record, $this->tableFieldsInfo, $ssFilters);
                if (empty($parsed)) {
                    throw new BadRequestException('No valid fields were found in record.');
                }

                $item = [
                    static::TABLE_INDICATOR => $this->transactionTable,
                    'Item'                  => $this->formatAttributes($parsed),
                    'ConditionExpression'   => "attribute_not_exists($idFields[0])",
                ];

                $this->getConnection()->putItem($item);

                if ($rollback) {
                    $key = static::buildKey($this->tableIdsInfo, $record);
                    $this->addToRollback($key);
                }

                $out = static::cleanRecord($record, $fields, $idFields);
                break;
            case Verbs::PUT:
                if (!empty($updates)) {
                    // only update by full records can use batching
                    $updates[$idFields[0]] = $id;
                    $record = $updates;
                }

                $parsed = $this->parseRecord($record, $this->tableFieldsInfo, $ssFilters, true);
                if (empty($parsed)) {
                    throw new BadRequestException('No valid fields were found in record.');
                }

                $native = $this->formatAttributes($parsed);

                $upsert = $this->parent->upsertAllowed();
                if (!$continue && !$rollback && !$upsert) {
                    return parent::addToTransaction($native, $id);
                }

                $options = ($rollback) ? ReturnValue::ALL_OLD : ReturnValue::NONE;
                $item = [
                    static::TABLE_INDICATOR => $this->transactionTable,
                    'Item'                  => $native,
                    'ReturnValues'          => $options,
                ];

                if (!$upsert) {
                    $item['ConditionExpression'] = "attribute_exists($idFields[0])";
                }

                $result = $this->getConnection()->putItem($item);

                if ($rollback) {
                    $temp = $result['Attributes'];
                    if (!empty($temp)) {
                        $this->addToRollback($temp);
                    }
                }

                $out = static::cleanRecord($record, $fields, $idFields);
                break;

            case Verbs::PATCH:
                if (!empty($updates)) {
                    $updates[$idFields[0]] = $id;
                    $record = $updates;
                }

                $parsed = $this->parseRecord($record, $this->tableFieldsInfo, $ssFilters, true);
                if (empty($parsed)) {
                    throw new BadRequestException('No valid fields were found in record.');
                }

                $key = static::buildKey($this->tableIdsInfo, $parsed, true);
                $marshaler = new Marshaler();
                $expression = [];
                $outNames = [];
                $outParams = [];
                foreach ($parsed as $name => &$value) {
                    $outNames['#' . $name] = $name;
                    $outParams[':' . $name] = $marshaler->marshalValue($value);
                    $expression[] = "#$name = :$name";
                }

                $expression = (!empty($expression) ? 'SET ' . implode(', ', $expression) : null);

                // simple insert request
                $options = ($rollback) ? ReturnValue::ALL_OLD : ReturnValue::ALL_NEW;

                $result = $this->getConnection()->updateItem(
                    [
                        static::TABLE_INDICATOR     => $this->transactionTable,
                        'Key'                       => $key,
                        'UpdateExpression'          => $expression,
                        'ExpressionAttributeNames'  => $outNames,
                        'ExpressionAttributeValues' => $outParams,
                        'ReturnValues'              => $options
                    ]
                );

                $temp = $result['Attributes'];
                if ($rollback) {
                    $this->addToRollback($temp);

                    // merge old record with new changes
                    $new = array_merge($this->unformatAttributes($temp), $updates);
                    $out = static::cleanRecord($new, $fields, $idFields);
                } else {
                    $temp = $this->unformatAttributes($temp);
                    $out = static::cleanRecord($temp, $fields, $idFields);
                }
                break;

            case Verbs::DELETE:
                if (!$continue && !$rollback) {
                    return parent::addToTransaction(null, $id);
                }

                $record = [$idFields[0] => $id];
                $key = static::buildKey($this->tableIdsInfo, $record);

                $result = $this->getConnection()->deleteItem(
                    [
                        static::TABLE_INDICATOR => $this->transactionTable,
                        'Key'                   => $key,
                        'ReturnValues'          => ReturnValue::ALL_OLD,
                    ]
                );

                $temp = $result['Attributes'];

                if ($rollback) {
                    $this->addToRollback($temp);
                }

                $temp = $this->unformatAttributes($temp);
                $out = static::cleanRecord($temp, $fields, $idFields);
                break;

            case Verbs::GET:
                $record = [$idFields[0] => $id];
                $key = static::buildKey($this->tableIdsInfo, $record);
                $scanProperties = [
                    static::TABLE_INDICATOR => $this->transactionTable,
                    'Key'                   => $key,
                    'ConsistentRead'        => true,
                ];

                $fields = static::buildProjectionExpression($fields, $idFields);
                if (!empty($fields)) {
                    $scanProperties['ProjectionExpression'] = $fields;
                }

                $result = $this->getConnection()->getItem($scanProperties);
                $result = $result['Item'];
                if (empty($result)) {
                    throw new NotFoundException('Record not found.');
                }

                // Grab value from the result object like an array
                $out = $this->unformatAttributes($result);
                break;
            default:
                break;
        }

        return $out;
    }
protected function addToTransaction(
        $record = null,
        $id = null,
        $extras = null,
        $rollback = false,
        $continue = false,
        $single = false
    ) {
        $ssFilters = array_get($extras, 'ss_filters');
        $fields = array_get($extras, ApiOptions::FIELDS);
        $idFields = array_get($extras, 'id_fields');
        $updates = array_get($extras, 'updates');

        $out = [];
        switch ($this->getAction()) {
            case Verbs::POST:
                $parsed = $this->parseRecord($record, $this->tableFieldsInfo, $ssFilters);
                if (empty($parsed)) {
                    throw new BadRequestException('No valid fields were found in record.');
                }

                $item = [
                    static::TABLE_INDICATOR => $this->transactionTable,
                    'Item'                  => $this->formatAttributes($parsed),
                    'ConditionExpression'   => "attribute_not_exists($idFields[0])",
                ];

                $this->getConnection()->putItem($item);

                if ($rollback) {
                    $key = static::buildKey($this->tableIdsInfo, $record);
                    $this->addToRollback($key);
                }

                $out = static::cleanRecord($record, $fields, $idFields);
                break;
            case Verbs::PUT:
                if (!empty($updates)) {
                    // only update by full records can use batching
                    $updates[$idFields[0]] = $id;
                    $record = $updates;
                }

                $parsed = $this->parseRecord($record, $this->tableFieldsInfo, $ssFilters, true);
                if (empty($parsed)) {
                    throw new BadRequestException('No valid fields were found in record.');
                }

                $native = $this->formatAttributes($parsed);

                $upsert = $this->parent->upsertAllowed();
                if (!$continue && !$rollback && !$upsert) {
                    return parent::addToTransaction($native, $id);
                }

                $options = ($rollback) ? ReturnValue::ALL_OLD : ReturnValue::NONE;
                $item = [
                    static::TABLE_INDICATOR => $this->transactionTable,
                    'Item'                  => $native,
                    'ReturnValues'          => $options,
                ];

                if (!$upsert) {
                    $item['ConditionExpression'] = "attribute_exists($idFields[0])";
                }

                $result = $this->getConnection()->putItem($item);

                if ($rollback) {
                    $temp = $result['Attributes'];
                    if (!empty($temp)) {
                        $this->addToRollback($temp);
                    }
                }

                $out = static::cleanRecord($record, $fields, $idFields);
                break;

            case Verbs::PATCH:
                if (!empty($updates)) {
                    $updates[$idFields[0]] = $id;
                    $record = $updates;
                }

                $parsed = $this->parseRecord($record, $this->tableFieldsInfo, $ssFilters, true);
                if (empty($parsed)) {
                    throw new BadRequestException('No valid fields were found in record.');
                }

                $key = static::buildKey($this->tableIdsInfo, $parsed, true);
                $marshaler = new Marshaler();
                $expression = [];
                $outNames = [];
                $outParams = [];
                foreach ($parsed as $name => &$value) {
                    $outNames['#' . $name] = $name;
                    $outParams[':' . $name] = $marshaler->marshalValue($value);
                    $expression[] = "#$name = :$name";
                }

                $expression = (!empty($expression) ? 'SET ' . implode(', ', $expression) : null);

                // simple insert request
                $options = ($rollback) ? ReturnValue::ALL_OLD : ReturnValue::ALL_NEW;

                $result = $this->getConnection()->updateItem(
                    [
                        static::TABLE_INDICATOR     => $this->transactionTable,
                        'Key'                       => $key,
                        'UpdateExpression'          => $expression,
                        'ExpressionAttributeNames'  => $outNames,
                        'ExpressionAttributeValues' => $outParams,
                        'ReturnValues'              => $options
                    ]
                );

                $temp = $result['Attributes'];
                if ($rollback) {
                    $this->addToRollback($temp);

                    // merge old record with new changes
                    $new = array_merge($this->unformatAttributes($temp), $updates);
                    $out = static::cleanRecord($new, $fields, $idFields);
                } else {
                    $temp = $this->unformatAttributes($temp);
                    $out = static::cleanRecord($temp, $fields, $idFields);
                }
                break;

            case Verbs::DELETE:
                if (!$continue && !$rollback) {
                    return parent::addToTransaction(null, $id);
                }

                $record = [$idFields[0] => $id];
                $key = static::buildKey($this->tableIdsInfo, $record);

                $result = $this->getConnection()->deleteItem(
                    [
                        static::TABLE_INDICATOR => $this->transactionTable,
                        'Key'                   => $key,
                        'ReturnValues'          => ReturnValue::ALL_OLD,
                    ]
                );

                $temp = $result['Attributes'];

                if ($rollback) {
                    $this->addToRollback($temp);
                }

                $temp = $this->unformatAttributes($temp);
                $out = static::cleanRecord($temp, $fields, $idFields);
                break;

            case Verbs::GET:
                $record = [$idFields[0] => $id];
                $key = static::buildKey($this->tableIdsInfo, $record);
                $scanProperties = [
                    static::TABLE_INDICATOR => $this->transactionTable,
                    'Key'                   => $key,
                    'ConsistentRead'        => true,
                ];

                $fields = static::buildProjectionExpression($fields, $idFields);
                if (!empty($fields)) {
                    $scanProperties['ProjectionExpression'] = $fields;
                }

                $result = $this->getConnection()->getItem($scanProperties);
                $result = $result['Item'];
                if (empty($result)) {
                    throw new NotFoundException('Record not found.');
                }

                // Grab value from the result object like an array
                $out = $this->unformatAttributes($result);
                break;
            default:
                break;
        }

        return $out;
    }
{@inheritdoc}