Skip to content

Commit d22b285

Browse files
committed
fix(lib-dynamodb): remove unnecessary copying
1 parent 619d70a commit d22b285

File tree

2 files changed

+14
-67
lines changed

2 files changed

+14
-67
lines changed
Lines changed: 11 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { setFeature } from "@aws-sdk/core";
2-
import { NumberValueImpl as NumberValue } from "@aws-sdk/util-dynamodb";
32
import { Command as $Command } from "@smithy/smithy-client";
43
import {
54
DeserializeHandler,
@@ -43,32 +42,25 @@ export abstract class DynamoDBDocumentClientCommand<
4342
marshallOptions.convertTopLevelContainer = marshallOptions.convertTopLevelContainer ?? true;
4443
unmarshallOptions.convertWithoutMapWrapper = unmarshallOptions.convertWithoutMapWrapper ?? true;
4544

46-
this.clientCommand.middlewareStack.add(
45+
this.clientCommand.middlewareStack.addRelativeTo(
4746
(next: InitializeHandler<Input | BaseInput, Output | BaseOutput>, context: HandlerExecutionContext) =>
4847
async (
4948
args: InitializeHandlerArguments<Input | BaseInput>
5049
): Promise<InitializeHandlerOutput<Output | BaseOutput>> => {
50+
setFeature(context, "DDB_MAPPER", "d");
5151
return next({
5252
...args,
53-
input: this.getCommandInput(),
53+
/**
54+
* We overwrite `args.input` at this middleware, but do not
55+
* mutate the args object itself, which is initially the Command instance.
56+
*
57+
* The reason for this is to prevent mutations to the Command instance's inputs
58+
* from being carried over if the Command instance is reused in a new
59+
* request.
60+
*/
61+
input: marshallInput(args.input, this.inputKeyNodes, marshallOptions),
5462
});
5563
},
56-
{
57-
name: "DocumentInitCopyInput",
58-
step: "initialize",
59-
priority: "high",
60-
override: true,
61-
}
62-
);
63-
this.clientCommand.middlewareStack.addRelativeTo(
64-
(next: InitializeHandler<Input | BaseInput, Output | BaseOutput>, context: HandlerExecutionContext) =>
65-
async (
66-
args: InitializeHandlerArguments<Input | BaseInput>
67-
): Promise<InitializeHandlerOutput<Output | BaseOutput>> => {
68-
setFeature(context, "DDB_MAPPER", "d");
69-
args.input = marshallInput(args.input, this.inputKeyNodes, marshallOptions);
70-
return next(args);
71-
},
7264
{
7365
name: "DocumentMarshall",
7466
relation: "before",
@@ -93,46 +85,4 @@ export abstract class DynamoDBDocumentClientCommand<
9385
}
9486
);
9587
}
96-
97-
/**
98-
* For snapshotting the user input as the request starts.
99-
* The reason for this is to prevent mutations to the Command instance's inputs
100-
* from being carried over if the Command instance is reused in a new
101-
* request.
102-
*/
103-
private getCommandInput(): Input | BaseInput {
104-
return this.documentClone(this.input);
105-
}
106-
107-
/**
108-
* Recursive clone of types applicable to DynamoDBDocument.
109-
*/
110-
private documentClone(it: any): any {
111-
if (it === null || it === undefined) {
112-
return it;
113-
}
114-
if (it instanceof Set) {
115-
return new Set(it.values());
116-
}
117-
if (it instanceof Map) {
118-
return new Map(it.entries());
119-
}
120-
if (typeof it === "object") {
121-
if (it instanceof NumberValue) {
122-
return new NumberValue(it.value);
123-
}
124-
if (it instanceof Uint8Array) {
125-
return new Uint8Array(it);
126-
}
127-
if (Array.isArray(it)) {
128-
return it.map((i) => this.documentClone(i));
129-
}
130-
const out = {} as any;
131-
for (const [key, value] of Object.entries(it)) {
132-
out[key] = this.documentClone(value);
133-
}
134-
return out;
135-
}
136-
return it;
137-
}
13888
}

lib/lib-dynamodb/src/test/mutability.integ.spec.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,9 @@ describe("DynamoDBDocument command mutability", () => {
8888
await doc.send(command);
8989

9090
// params should remain what it was set to by the caller,
91-
// disregarding middleware modifications and mutations
92-
// applied by the marshaller.
91+
// disregarding mutations applied by the AttributeValue marshaller.
9392
expect(params).toEqual({
94-
TableName: "test",
93+
TableName: "modified-by-middleware",
9594
FilterExpression: "id = :id",
9695
ExpressionAttributeValues: {
9796
":id": "1",
@@ -184,7 +183,7 @@ describe("DynamoDBDocument command mutability", () => {
184183
await ddb.send(command);
185184

186185
// for regular clients, middleware modifications to the
187-
// args.input object persist beyond the request.
186+
// args.input object also persist beyond the request.
188187
expect(params).toEqual({
189188
TableName: "modified-by-middleware",
190189
FilterExpression: "id = :id",
@@ -250,8 +249,6 @@ describe("DynamoDBDocument command mutability", () => {
250249
params.Bucket = `bucket4`;
251250
await s3.send(command);
252251

253-
// for regular clients, middleware modifications to the
254-
// args.input object persist beyond the request.
255252
expect(params).toEqual({
256253
Bucket: "bucket4",
257254
ExpectedBucketOwner: "me",

0 commit comments

Comments
 (0)