Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(lib-dynamodb): make command middleware useable, turn marshalling into middleware #3808

Merged
merged 5 commits into from Aug 1, 2022

Conversation

kuhe
Copy link
Contributor

@kuhe kuhe commented Jul 19, 2022

revision 2 of #3756

Issue

#3095
current workaround: add middleware to the client instead of individual Commands.

Description

  • turns the "marshall" and "unmarshall" transform steps of the @aws-sdk/lib-dynamodb package into middleware on its client.
  • allow use of middleware on individual Commands in that package

Testing

  • add unit test
  • integration testing w/ dynamodb

@kuhe kuhe force-pushed the 3095-lib-dynamodb-rev2 branch 4 times, most recently from d7ed623 to 59910f2 Compare July 20, 2022 16:32
@kuhe
Copy link
Contributor Author

kuhe commented Jul 21, 2022

test script:

import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
  BatchExecuteStatementCommand,
  DynamoDBDocument,
  DynamoDBDocumentClientCommand,
    QueryCommandInput as ClientQueryCommandInput,
  QueryCommandInput as LibQueryCommandInput,
    QueryCommandOutput as ClientQueryCommandOutput,
  QueryCommandOutput as LibQueryCommandOutput,
  UpdateCommand,
} from "@aws-sdk/lib-dynamodb";
import { InitializeHandler, InitializeHandlerArguments } from "@aws-sdk/types";
import assert from "assert";

const client: DynamoDBClient = new DynamoDBClient({ region: "us-east-1" });

const doc = DynamoDBDocument.from(client);

const timeout = setTimeout(() => {}, 60000);

(async () => {
  const tableName = "test-3095";
  console.log("starting");

  console.log("batch execute deletes");
  const batchExecuteStatementCommand = new BatchExecuteStatementCommand({
    Statements: [
      {
        Statement: `delete
                            from "${tableName}"
                            where "pk" = 'eins'`,
      },
      {
        Statement: `delete
                            from "${tableName}"
                            where "pk" = 'zwei'`,
      },
      {
        Statement: `delete
                            from "${tableName}"
                            where "pk" = 'drei'`,
      },
    ],
  });
  // inspectCommand(batchExecuteStatementCommand);
  await doc.send(batchExecuteStatementCommand);

  console.log("batch get 0");
  let batchGet = await doc.batchGet({
    RequestItems: {
      [tableName]: {
        Keys: [{ pk: "eins" }, { pk: "zwei" }],
      },
    },
  });

  assert(batchGet.Responses[tableName].length === 0);

  console.log("batch execute statement");
  const batchExecuteStatement = await doc.batchExecuteStatement({
    Statements: [
      {
        Statement: `insert into "${tableName}" value {'pk': 'eins', 'eng': 'one'}`,
      },
      {
        Statement: `insert into "${tableName}" value {'pk': 'zwei', 'eng': 'two'}`,
      },
    ],
  });
  assert(batchExecuteStatement.Responses.length === 2);
  assert(batchExecuteStatement.Responses[0].TableName);

  console.log("batch get 1");
  batchGet = await doc.batchGet({
    RequestItems: {
      [tableName]: {
        Keys: [{ pk: "eins" }, { pk: "zwei" }],
      },
    },
  });

  assert(batchGet.Responses[tableName].length === 2);
  assert(batchGet.Responses[tableName].find((_) => _.pk === "zwei").eng === "two");

  console.log("batch write");
  await doc.batchWrite({
    RequestItems: {
      [tableName]: [
        {
          PutRequest: {
            Item: {
              pk: "eins",
              eng: "one",
            },
          },
        },
        {
          PutRequest: {
            Item: {
              pk: "zwei",
              eng: "two",
            },
          },
        },
      ],
    },
  });
  console.log("batch get 2");
  batchGet = await doc.batchGet({
    RequestItems: {
      [tableName]: {
        Keys: [{ pk: "eins" }, { pk: "zwei" }],
      },
    },
  });
  assert(batchGet.Responses[tableName].length === 2);
  assert(batchGet.Responses[tableName].find((_) => _.pk === "zwei").eng === "two");

  console.log("delete");
  await doc.delete({
    TableName: tableName,
    Key: {
      pk: "eins",
    },
  });

  console.log("executeStatement");
  await doc.executeStatement({
    Statement: `delete
                    from "${tableName}"
                    where "pk" = 'eins'`,
  });

  console.log("get");
  const get = await doc.get({
    TableName: tableName,
    Key: {
      pk: "zwei",
    },
  });
  assert(get.Item.eng === "two");

  console.log("put");
  const put = await doc.put({
    TableName: tableName,
    Item: {
      pk: "eins",
      eng: "one",
      list: [3, 4, 5],
    },
  });

  console.log("query");
  const query = await doc.query({
    ExpressionAttributeValues: {
      ":pk": "eins",
    },
    KeyConditionExpression: "pk = :pk",
    TableName: tableName,
  });
  assert(query.Items.length === 1);
  assert(query.Items[0].eng === "one");

  console.log("scan");
  const scan = await doc.scan({
    FilterExpression: 'eng = :eng',
    ExpressionAttributeValues: {
      ":eng": "two",
    },
    TableName: tableName
  });
  assert(scan.Items.length === 1)
  assert(scan.Items[0].pk === 'zwei')

  const updateCommand = new UpdateCommand({
    TableName: tableName,
    Key: {
      pk: "eins",
    },
    AttributeUpdates: {
      list: {
        Action: "PUT",
        Value: 'list fails', // TODO
      },
      map: {
        Action: "PUT",
        Value: 'map fails', // TODO
      },
    },
  });
  inspectCommand(updateCommand);

  console.log("update");
  const update = await doc.send(updateCommand);

  console.log("ending");
  clearTimeout(timeout);
})();

function inspectCommand(command: DynamoDBDocumentClientCommand<any, any, any, any, any>) {
  command.middlewareStack.addRelativeTo(
    (next: InitializeHandler<ClientQueryCommandInput, ClientQueryCommandOutput>) =>
      async (args: InitializeHandlerArguments<ClientQueryCommandInput>) => {
        console.log("pre-marshall", JSON.stringify(args.input, null, 2));
        return next(args);
      },
    {
      name: "pre-marshall debug",
      override: true,
      relation: "before",
      toMiddleware: "DocumentMarshall",
    }
  );
  command.middlewareStack.addRelativeTo(
    (next: InitializeHandler<LibQueryCommandInput, LibQueryCommandOutput>) =>
      async (args: InitializeHandlerArguments<LibQueryCommandInput>) => {
        console.log("post-marshall", JSON.stringify(args.input, null, 2));
        return next(args);
      },
    {
      name: "post-marshall debug",
      override: true,
      relation: "after",
      toMiddleware: "DocumentMarshall",
    }
  );

  command.middlewareStack.addRelativeTo(
    (next) => async (args) => {
      const result = await next(args);
      console.log("post-unmarshall", JSON.stringify(result.output, null, 2));
      return result;
    },
    {
      name: "post-unmarshall debug",
      override: true,
      relation: "before",
      toMiddleware: "DocumentUnmarshall",
    }
  );
  command.middlewareStack.addRelativeTo(
    (next) => async (args) => {
      const result = await next(args);
      console.log("pre-unmarshall", JSON.stringify(result.output, null, 2));
      return result;
    },
    {
      name: "pre-unmarshall debug",
      override: true,
      relation: "after",
      toMiddleware: "DocumentUnmarshall",
    }
  );
}

@kuhe kuhe marked this pull request as ready for review July 21, 2022 17:16
@kuhe kuhe requested a review from a team as a code owner July 21, 2022 17:16
lib/lib-dynamodb/src/commands/BatchGetCommand.ts Outdated Show resolved Hide resolved
lib/lib-dynamodb/src/commands/BatchGetCommand.ts Outdated Show resolved Hide resolved
@kuhe kuhe merged commit 38b1a28 into aws:main Aug 1, 2022
@kuhe kuhe deleted the 3095-lib-dynamodb-rev2 branch August 1, 2022 17:04
@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants