Repository: getmoto/moto

Issue:
bug: dynamodb2 transact_get_items should return empty Map for item, if item not found
AWS documentation https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_TransactGetItems.html
"If a requested item could not be retrieved, the corresponding ItemResponse object is Null, or if the requested item has no projected attributes, the corresponding ItemResponse object is an empty Map."

Short example:
Put into some table only one value
    "Get": {
      "Key": {
        "primaryKey": {
          "S": "primarykey1"
        }
      },
      "TableName": "TestTable"
    }
Then transact_get_items, from both AWS and moto dynomodb2
[
  {
    "Get": {
      "Key": {
        "primaryKey": {
          "S": "primarykey1"
        }
      },
      "TableName": "TestTable"
    }
  }
  {
    "Get": {
      "Key": {
        "primaryKey": {
          "S": "primarykey2"
        }
      },
      "TableName": "TestTable"
    }
  }
]

AWS response: [
  {
    "Get": {
      "Key": {
        "primaryKey": {
          "S": "primarykey1"
        }
      },
      "TableName": "TestTable"
    }
  },
  {}
]

Moto dynamodb2 response
[
  {
    "Get": {
      "Key": {
        "primaryKey": {
          "S": "primarykey1"
        }
      },
      "TableName": "TestTable"
    }
  }    # HERE THE SECOND EMPTY ITEM IS MISSING
]





Discussion:
Thanks for raising this @palloromk!
My first issue, so pretty exciting for me :D I am just a beginner.
@palloromk Did you want to take a crack at fixing this?  I'm happy to do it myself, but didn't want to steal your thunder if you were planning to write the PR.  Let me know.  Thanks.

Resolving patch:
diff --git a/moto/dynamodb2/responses.py b/moto/dynamodb2/responses.py
--- a/moto/dynamodb2/responses.py
+++ b/moto/dynamodb2/responses.py
@@ -906,6 +906,7 @@ def transact_get_items(self):
                 return self.error(er, "Requested resource not found")
 
             if not item:
+                responses.append({})
                 continue
 
             item_describe = item.describe_attrs(False)


Test patch:
diff --git a/tests/test_dynamodb2/test_dynamodb.py b/tests/test_dynamodb2/test_dynamodb.py
--- a/tests/test_dynamodb2/test_dynamodb.py
+++ b/tests/test_dynamodb2/test_dynamodb.py
@@ -4285,7 +4285,8 @@ def test_valid_transact_get_items():
         ]
     )
     res["Responses"][0]["Item"].should.equal({"id": {"S": "1"}, "sort_key": {"S": "1"}})
-    len(res["Responses"]).should.equal(1)
+    len(res["Responses"]).should.equal(2)
+    res["Responses"][1].should.equal({})
 
     res = client.transact_get_items(
         TransactItems=[
@@ -5479,3 +5480,28 @@ def test_set_attribute_is_dropped_if_empty_after_update_expression():
     item = resp["Items"][0]
     item.should.have.key("customer")
     item.should_not.have.key("orders")
+
+
+@mock_dynamodb2
+def test_transact_get_items_should_return_empty_map_for_non_existent_item():
+    client = boto3.client("dynamodb", region_name="us-west-2")
+    table_name = "test-table"
+    key_schema = [{"AttributeName": "id", "KeyType": "HASH"}]
+    attribute_definitions = [{"AttributeName": "id", "AttributeType": "S"}]
+    client.create_table(
+        TableName=table_name,
+        KeySchema=key_schema,
+        AttributeDefinitions=attribute_definitions,
+        ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
+    )
+    item = {"id": {"S": "1"}}
+    client.put_item(TableName=table_name, Item=item)
+    items = client.transact_get_items(
+        TransactItems=[
+            {"Get": {"Key": {"id": {"S": "1"}}, "TableName": table_name}},
+            {"Get": {"Key": {"id": {"S": "2"}}, "TableName": table_name}},
+        ]
+    ).get("Responses", [])
+    items.should.have.length_of(2)
+    items[0].should.equal({"Item": item})
+    items[1].should.equal({})