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
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
import software.amazon.smithy.codegen.core.CodegenException;
Expand Down Expand Up @@ -54,6 +56,10 @@ final class DocumentClientCommandGenerator implements Runnable {
private final List<MemberShape> outputMembersWithAttr;
private final String clientCommandClassName;
private final String clientCommandLocalName;
private final String helperTypePrefix;
private final Map<String, String> structureHelperTypeNames = new LinkedHashMap<>();
private final List<StructureShape> structureHelperTypes = new ArrayList<>();
private final Set<String> reservedHelperTypeNames = new HashSet<>();
/**
* Map of package name to external:local name entries.
*/
Expand Down Expand Up @@ -89,6 +95,9 @@ final class DocumentClientCommandGenerator implements Runnable {

clientCommandClassName = symbol.getName();
clientCommandLocalName = "__" + clientCommandClassName;
helperTypePrefix = DocumentClientUtils.getModifiedName(symbol.getName().replaceAll("Command$", ""));
reservedHelperTypeNames.add(inputTypeName);
reservedHelperTypeNames.add(outputTypeName);
}

@Override
Expand Down Expand Up @@ -320,13 +329,51 @@ private void writeStructureKeyNode(StructureShape structureTarget) {
}

private void generateInputAndOutputTypes() {
collectHelperTypes(inputMembersWithAttr);
collectHelperTypes(outputMembersWithAttr);

for (StructureShape structureShape : structureHelperTypes) {
writer.write("");
writeNamedStructureOmitType(structureShape);
}

writer.write("");
writeType(inputTypeName, originalInputTypeName, operationIndex.getInput(operation), inputMembersWithAttr);
writer.write("");
writeType(outputTypeName, originalOutputTypeName, operationIndex.getOutput(operation), outputMembersWithAttr);
writer.write("");
}

private void collectHelperTypes(List<MemberShape> membersWithAttr) {
for (MemberShape member : membersWithAttr) {
collectHelperTypes(member, new HashSet<>());
}
}

private void collectHelperTypes(MemberShape member, Set<String> parents) {
Shape memberTarget = model.expectShape(member.getTarget());
if (memberTarget.isStructureShape()) {
StructureShape structureTarget = (StructureShape) memberTarget;
String structureId = structureTarget.getId().toString();
if (!parents.add(structureId)) {
return;
}

List<MemberShape> membersWithAttr = getStructureMembersWithAttr(Optional.of(structureTarget));
for (MemberShape memberWithAttr : membersWithAttr) {
collectHelperTypes(memberWithAttr, parents);
}
if (!membersWithAttr.isEmpty()) {
getStructureHelperTypeName(structureTarget);
}
parents.remove(structureId);
} else if (memberTarget.isMapShape()) {
collectHelperTypes(((MapShape) memberTarget).getValue(), parents);
} else if (memberTarget instanceof CollectionShape) {
collectHelperTypes(((CollectionShape) memberTarget).getMember(), parents);
}
}

private List<MemberShape> getStructureMembersWithAttr(Optional<StructureShape> optionalShape) {
List<MemberShape> membersWithAttr = new ArrayList<>();
if (DocumentClientUtils.containsAttributeValue(model, symbolProvider, optionalShape)) {
Expand Down Expand Up @@ -378,20 +425,18 @@ private void writeType(
}
}

private void writeStructureOmitType(StructureShape structureTarget) {
private void writeNamedStructureOmitType(StructureShape structureTarget) {
List<MemberShape> membersWithAttr = getStructureMembersWithAttr(Optional.of(structureTarget));
String memberUnionToOmit = membersWithAttr.stream()
.map(memberWithAttr -> "'" + symbolProvider.toMemberName(memberWithAttr) + "'")
.collect(Collectors.joining(" | "));
String typeNameToOmit = symbolProvider.toSymbol(structureTarget).getName();
registerTypeImport(
typeNameToOmit,
typeNameToOmit,
AwsDependency.CLIENT_DYNAMODB_PEER.getPackageName()
);
String typeNameToOmit = getStructureBaseTypeName(structureTarget);

writer.writeDocs("@public");
writer.openBlock(
"Omit<$L, $L> & {",
"}",
"export type $L = Omit<$L, $L> & {",
"};",
getStructureHelperTypeName(structureTarget),
typeNameToOmit,
memberUnionToOmit,
() -> {
Expand All @@ -418,7 +463,7 @@ private void writeStructureMemberOmitType(MemberShape member) {
private void writeMemberOmitType(MemberShape member, boolean allowUndefined) {
Shape memberTarget = model.expectShape(member.getTarget());
if (memberTarget.isStructureShape()) {
writeStructureOmitType((StructureShape) memberTarget);
writer.write(getStructureHelperTypeName((StructureShape) memberTarget));
} else if (memberTarget.isUnionShape()) {
if (symbolProvider.toSymbol(memberTarget).getName().equals("AttributeValue")) {
writeNativeAttributeValue();
Expand Down Expand Up @@ -448,6 +493,40 @@ private void writeMemberOmitType(MemberShape member, boolean allowUndefined) {
}
}

private String getStructureHelperTypeName(StructureShape structureTarget) {
String structureId = structureTarget.getId().toString();
if (structureHelperTypeNames.containsKey(structureId)) {
return structureHelperTypeNames.get(structureId);
}

String shapeName = symbolProvider.toSymbol(structureTarget).getName();
String preferredName = shapeName.startsWith(helperTypePrefix)
? shapeName
: helperTypePrefix + shapeName;
String helperTypeName = preferredName;
int collisionSuffix = 2;
while (!reservedHelperTypeNames.add(helperTypeName)) {
helperTypeName = preferredName + collisionSuffix++;
}

structureHelperTypeNames.put(structureId, helperTypeName);
structureHelperTypes.add(structureTarget);
return helperTypeName;
}

private String getStructureBaseTypeName(StructureShape structureTarget) {
String externalName = symbolProvider.toSymbol(structureTarget).getName();
String helperTypeName = getStructureHelperTypeName(structureTarget);
String localName = externalName.equals(helperTypeName) ? "Client" + externalName : externalName;

registerTypeImport(
externalName,
localName,
AwsDependency.CLIENT_DYNAMODB_PEER.getPackageName()
);
return localName;
}

private void writeNativeAttributeValue() {
String nativeAttributeValue = "NativeAttributeValue";
registerTypeImport(
Expand Down
143 changes: 61 additions & 82 deletions lib/lib-dynamodb/src/commands/BatchExecuteStatementCommand.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
// smithy-typescript generated code
import { BatchExecuteStatementCommand as __BatchExecuteStatementCommand } from "@aws-sdk/client-dynamodb";
import { Command as $Command } from "@smithy/smithy-client";
import { type HttpHandlerOptions as __HttpHandlerOptions, Handler, MiddlewareStack } from "@smithy/types";
import type { Handler, MiddlewareStack } from "@smithy/types";
import { type HttpHandlerOptions as __HttpHandlerOptions } from "@smithy/types";

import { DynamoDBDocumentClientCommand } from "../baseCommand/DynamoDBDocumentClientCommand";
import { ALL_MEMBERS, ALL_VALUES } from "../commands/utils";
import { DynamoDBDocumentClientResolvedConfig, ServiceInputTypes, ServiceOutputTypes } from "../DynamoDBDocumentClient";
import { BatchExecuteStatementCommand as __BatchExecuteStatementCommand } from "@aws-sdk/client-dynamodb";
import type {
DynamoDBDocumentClientResolvedConfig,
ServiceInputTypes,
ServiceOutputTypes,
} from "../DynamoDBDocumentClient";

/**
* @public
Expand All @@ -15,50 +20,37 @@ export { DynamoDBDocumentClientCommand, $Command };
/**
* @public
*/
export type BatchExecuteStatementCommandInput = Omit<__BatchExecuteStatementCommandInput, 'Statements'> & {
Statements:
(
Omit<BatchStatementRequest, 'Parameters'> & {
Parameters?:
(
NativeAttributeValue
)[]
| undefined
;
}
)[]
| undefined
;
export type BatchExecuteStatementBatchStatementRequest = Omit<BatchStatementRequest, "Parameters"> & {
Parameters?: NativeAttributeValue[] | undefined;
};

/**
* @public
*/
export type BatchExecuteStatementBatchStatementError = Omit<BatchStatementError, "Item"> & {
Item?: Record<string, NativeAttributeValue> | undefined;
};

/**
* @public
*/
export type BatchExecuteStatementBatchStatementResponse = Omit<BatchStatementResponse, "Error" | "Item"> & {
Error?: BatchExecuteStatementBatchStatementError | undefined;
Item?: Record<string, NativeAttributeValue> | undefined;
};

/**
* @public
*/
export type BatchExecuteStatementCommandOutput = Omit<__BatchExecuteStatementCommandOutput, 'Responses'> & {
Responses?:
(
Omit<BatchStatementResponse, 'Error' | 'Item'> & {
Error?:
Omit<BatchStatementError, 'Item'> & {
Item?:
Record<string,
NativeAttributeValue
>
| undefined
;
}
| undefined
;
Item?:
Record<string,
NativeAttributeValue
>
| undefined
;
}
)[]
| undefined
;
export type BatchExecuteStatementCommandInput = Omit<__BatchExecuteStatementCommandInput, "Statements"> & {
Statements: BatchExecuteStatementBatchStatementRequest[] | undefined;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just use the type BatchExecuteStatementCommandInput["Statements"]?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would hit a self-reference: BatchExecuteStatementCommandInput["Statements"] will expand to "the type of the Statements property on BatchExecuteStatementCommandInput". But BatchExecuteStatementCommandInput itself is currently being defined, and its Statements property’s type is exactly what we’re trying to specify, so we'll end up with a circular definition, and TypeScript generally can't resolve that as a meaningful alias.

A non-circular DRY version would look like:

export type BatchExecuteStatementStatements = BatchExecuteStatementBatchStatementRequest[] | undefined;
export type BatchExecuteStatementCommandInput = Omit<__BatchExecuteStatementCommandInput, "Statements"> & {
  Statements: BatchExecuteStatementStatements;

};

/**
* @public
*/
export type BatchExecuteStatementCommandOutput = Omit<__BatchExecuteStatementCommandOutput, "Responses"> & {
Responses?: BatchExecuteStatementBatchStatementResponse[] | undefined;
};

/**
Expand All @@ -70,42 +62,36 @@ export type BatchExecuteStatementCommandOutput = Omit<__BatchExecuteStatementCom
*
* @public
*/
export class BatchExecuteStatementCommand extends DynamoDBDocumentClientCommand<BatchExecuteStatementCommandInput, BatchExecuteStatementCommandOutput, __BatchExecuteStatementCommandInput, __BatchExecuteStatementCommandOutput, DynamoDBDocumentClientResolvedConfig> {
export class BatchExecuteStatementCommand extends DynamoDBDocumentClientCommand<
BatchExecuteStatementCommandInput,
BatchExecuteStatementCommandOutput,
__BatchExecuteStatementCommandInput,
__BatchExecuteStatementCommandOutput,
DynamoDBDocumentClientResolvedConfig
> {
protected readonly inputKeyNodes = {
'Statements':
{
'*':
{
'Parameters':
ALL_MEMBERS // set/list of AttributeValue
,
}
}
,
Statements: {
"*": {
Parameters: ALL_MEMBERS, // set/list of AttributeValue
},
},
};
protected readonly outputKeyNodes = {
'Responses':
{
'*':
{
'Error':
{
'Item':
ALL_VALUES // map with AttributeValue
,
}
,
'Item':
ALL_VALUES // map with AttributeValue
,
}
}
,
Responses: {
"*": {
Error: {
Item: ALL_VALUES, // map with AttributeValue
},
Item: ALL_VALUES, // map with AttributeValue
},
},
};

protected readonly clientCommand: __BatchExecuteStatementCommand;
public readonly middlewareStack: MiddlewareStack<BatchExecuteStatementCommandInput | __BatchExecuteStatementCommandInput,
BatchExecuteStatementCommandOutput | __BatchExecuteStatementCommandOutput>;
public readonly middlewareStack: MiddlewareStack<
BatchExecuteStatementCommandInput | __BatchExecuteStatementCommandInput,
BatchExecuteStatementCommandOutput | __BatchExecuteStatementCommandOutput
>;

constructor(readonly input: BatchExecuteStatementCommandInput) {
super();
Expand All @@ -121,26 +107,19 @@ export class BatchExecuteStatementCommand extends DynamoDBDocumentClientCommand<
configuration: DynamoDBDocumentClientResolvedConfig,
options?: __HttpHandlerOptions
): Handler<BatchExecuteStatementCommandInput, BatchExecuteStatementCommandOutput> {
this.addMarshallingMiddleware(
configuration
);
this.addMarshallingMiddleware(configuration);
const stack = clientStack.concat(this.middlewareStack as typeof clientStack);
const handler = this.clientCommand.resolveMiddleware(stack, configuration, options);

return async () => handler(this.clientCommand)
return async () => handler(this.clientCommand);
}
}

import type {
BatchExecuteStatementCommandInput as __BatchExecuteStatementCommandInput,

BatchExecuteStatementCommandOutput as __BatchExecuteStatementCommandOutput,

BatchStatementError,
BatchStatementRequest,
BatchStatementResponse,
} from "@aws-sdk/client-dynamodb";

import type {
NativeAttributeValue,
} from "@aws-sdk/util-dynamodb";
import type { NativeAttributeValue } from "@aws-sdk/util-dynamodb";
Loading