Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/core/src/validation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1661,7 +1661,7 @@ pub fn validate_select_projection(
}
if matches!(select, Some(Select::AllProjectedAttributes)) && !has_index_name {
return Err(DynamoDbError::ValidationException(
"ALL_PROJECTED_ATTRIBUTES can be used only when Querying using an IndexName".to_owned(),
"1 validation error detected: ALL_PROJECTED_ATTRIBUTES can be used only when Querying using an IndexName".to_owned(),
));
}
Ok(())
Expand Down Expand Up @@ -3457,7 +3457,7 @@ mod tests {
.unwrap_err();
assert_eq!(
err.to_string(),
"ALL_PROJECTED_ATTRIBUTES can be used only when Querying using an IndexName"
"1 validation error detected: ALL_PROJECTED_ATTRIBUTES can be used only when Querying using an IndexName"
);
assert!(
validate_select_projection(
Expand Down
3 changes: 2 additions & 1 deletion crates/engine/src/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,8 @@ pub async fn handle_scan(
&& index_info.is_none()
{
return Err(DynamoDbError::ValidationException(
"ALL_PROJECTED_ATTRIBUTES can be used only when Querying using an IndexName".to_owned(),
"1 validation error detected: ALL_PROJECTED_ATTRIBUTES can be used only when Querying using an IndexName"
.to_owned(),
));
}
if let Some(Select::Count) = input.select
Expand Down
83 changes: 83 additions & 0 deletions tests/test_select_all_projected_attributes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Copyright 2026 ExtendDB contributors
# SPDX-License-Identifier: Apache-2.0

"""Select=ALL_PROJECTED_ATTRIBUTES without an IndexName.

Amazon DynamoDB answers ``1 validation error detected:
ALL_PROJECTED_ATTRIBUTES can be used only when Querying using an IndexName``
on Query, with a KeyConditionExpression or legacy KeyConditions and with
ConsistentRead, and on Scan (measured 2026-10-25 at 21:13 UTC, us-east-1,
each request twice).

Dual-target against Amazon DynamoDB and extenddb.
"""

from __future__ import annotations

import pytest
from botocore.exceptions import ClientError

from conftest import scoped_table

MESSAGE = (
"1 validation error detected: "
"ALL_PROJECTED_ATTRIBUTES can be used only when Querying using an IndexName"
)


@pytest.fixture(scope="module")
def table(dynamodb_client):
with scoped_table(
dynamodb_client,
attribute_definitions=[
{"AttributeName": "pk", "AttributeType": "S"},
{"AttributeName": "sk", "AttributeType": "S"},
],
key_schema=[
{"AttributeName": "pk", "KeyType": "HASH"},
{"AttributeName": "sk", "KeyType": "RANGE"},
],
) as name:
yield name


def _message(func) -> str:
with pytest.raises(ClientError) as exc_info:
func()
err = exc_info.value.response["Error"]
assert err["Code"] == "ValidationException", err
return err["Message"]


@pytest.mark.parametrize("consistent", [False, True])
def test_query_key_condition_expression(dynamodb_client, table, consistent):
msg = _message(
lambda: dynamodb_client.query(
TableName=table,
KeyConditionExpression="pk = :p",
ExpressionAttributeValues={":p": {"S": "absent"}},
Select="ALL_PROJECTED_ATTRIBUTES",
ConsistentRead=consistent,
)
)
assert msg == MESSAGE


def test_query_legacy_key_conditions(dynamodb_client, table):
msg = _message(
lambda: dynamodb_client.query(
TableName=table,
KeyConditions={
"pk": {"ComparisonOperator": "EQ", "AttributeValueList": [{"S": "absent"}]}
},
Select="ALL_PROJECTED_ATTRIBUTES",
)
)
assert msg == MESSAGE


def test_scan(dynamodb_client, table):
msg = _message(
lambda: dynamodb_client.scan(TableName=table, Select="ALL_PROJECTED_ATTRIBUTES")
)
assert msg == MESSAGE
Loading