summaryrefslogtreecommitdiff
path: root/Homework/cs5260/consumer/dao/DynamoWidgetDAO.ts
blob: a90788fe3e3c26faecb751381e5a91350317cb7f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { Widget, WidgetT } from "@/shared/schema";
import { WidgetDAO } from ".";
import { TracingLogger } from "@/consumer/log";
import {
  AttributeValue,
  DeleteItemCommand,
  DynamoDBClient,
  GetItemCommand,
  PutItemCommand,
} from "@aws-sdk/client-dynamodb";

export class DynamoWidgetDAO implements WidgetDAO {
  private table: string;
  private ddbClient: DynamoDBClient;
  private logger: TracingLogger;

  constructor(table: string, ddbClient: DynamoDBClient, logger: TracingLogger) {
    this.table = table;
    this.ddbClient = ddbClient;
    this.logger = logger;
  }

  public async retrieve(widget: WidgetT) {
    const getReq = new GetItemCommand({
      TableName: this.table,
      Key: {
        id: {
          S: widget.id,
        },
      },
    });

    const response = await this.ddbClient.send(getReq);
    if (response.Item) {
      this.logger.info(`sucessfully retrieved Widget=(${widget.id})`);
      return this.deflate(response.Item);
    }
  }

  public async save(widget: WidgetT) {
    const putReq = new PutItemCommand({
      TableName: this.table,
      Item: this.inflate(widget),
    });

    await this.ddbClient.send(putReq);

    this.logger.info(`sucessfully saved Widget=(${widget.id})`);
    return widget;
  }

  public async delete(widget: WidgetT) {
    const deleteReq = new DeleteItemCommand({
      TableName: this.table,
      Key: {
        id: { S: widget.id },
      },
    });

    await this.ddbClient.send(deleteReq);

    this.logger.info(`sucessfully deleted Widget=(${widget.id})`);
    return widget;
  }

  private inflate(widget: WidgetT): Record<string, AttributeValue> {
    const additionalAttributes =
      widget.otherAttributes?.reduce((acc, { name, value }) => {
        acc[name] = { S: value };
        return acc;
      }, {} as Record<string, { S: string }>) ?? {};
    if (widget.label) additionalAttributes["label"] = { S: widget.label };
    if (widget.description)
      additionalAttributes["description"] = { S: widget.description };

    return {
      id: { S: widget.id },
      owner: { S: widget.owner },
      ...additionalAttributes,
    };
  }

  private deflate(item: Record<string, AttributeValue>): WidgetT {
    const respWidget = Object.keys(item).reduce((widge, key: string) => {
      const attributeValue = item![key];
      if (["id", "owner", "label", "description"].includes(key)) {
        widge[key] = attributeValue.S;
        return widge;
      }

      const attribute = { name: key, value: attributeValue.S! };
      widge["otherAttributes"] = widge["otherAttributes"]?.concat([
        attribute,
      ]) ?? [attribute];

      return widge;
    }, {} as Record<string, any>);
    return Widget.parse(respWidget);
  }
}