File size: 3,798 Bytes
2d78d32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
101
102
103
104
import * as cdk from 'aws-cdk-lib';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as cr from 'aws-cdk-lib/custom-resources';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
import { AppConfig } from './config';
import { generateSeedData } from './seed-data';

export interface DynamoDBStackProps extends cdk.StackProps {
  pointInTimeRecovery?: boolean;
  removalPolicy?: cdk.RemovalPolicy;
  deploymentEnvironment?: string;
  useStaticTableName?: boolean;
  config: AppConfig;
}

export class DynamoDBStack extends cdk.Stack {
  public readonly bonusClaimsTable: dynamodb.Table;

  constructor(scope: Construct, id: string, props: DynamoDBStackProps) {
    super(scope, id, props);

    // Create DynamoDB table with conditional naming
    const tableProps: Omit<dynamodb.TableProps, 'tableName'> = {
      partitionKey: { name: 'PK', type: dynamodb.AttributeType.STRING },
      sortKey: { name: 'SK', type: dynamodb.AttributeType.STRING },
      billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
      removalPolicy: props.removalPolicy || cdk.RemovalPolicy.DESTROY,
      pointInTimeRecoverySpecification: {
        pointInTimeRecoveryEnabled:
          props.pointInTimeRecovery !== undefined ? props.pointInTimeRecovery : true,
      },
    };

    // Create table with or without static name
    this.bonusClaimsTable = props.useStaticTableName
      ? new dynamodb.Table(this, 'BonusClaimsTable', {
          ...tableProps,
          tableName: `bonus-claims-${props.deploymentEnvironment || props.config.environment}`,
        })
      : new dynamodb.Table(this, 'BonusClaimsTable', tableProps);

    // Add GSI for querying by timestamp
    this.bonusClaimsTable.addGlobalSecondaryIndex({
      indexName: 'TimestampIndex',
      partitionKey: { name: 'PK', type: dynamodb.AttributeType.STRING },
      sortKey: { name: 'timestamp', type: dynamodb.AttributeType.STRING },
    });

    // Seed data using custom resource
    const seedDataRole = new iam.Role(this, 'SeedDataRole', {
      assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
    });

    seedDataRole.addManagedPolicy(
      iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole')
    );

    seedDataRole.addToPolicy(
      new iam.PolicyStatement({
        actions: ['dynamodb:BatchWriteItem', 'dynamodb:PutItem', 'dynamodb:DescribeTable'],
        resources: [this.bonusClaimsTable.tableArn],
      })
    );

    // Get seed data from the separate module
    const seedData = generateSeedData();

    // Create custom resource to seed data
    new cr.AwsCustomResource(this, 'SeedBonusClaimsData', {
      onCreate: {
        service: 'DynamoDB',
        action: 'batchWriteItem',
        parameters: {
          RequestItems: {
            [this.bonusClaimsTable.tableName]: seedData,
          },
        },
        physicalResourceId: cr.PhysicalResourceId.of(Date.now().toString()), // Use timestamp to force update
      },
      policy: cr.AwsCustomResourcePolicy.fromStatements([
        new iam.PolicyStatement({
          actions: ['dynamodb:BatchWriteItem', 'dynamodb:PutItem', 'dynamodb:DescribeTable'],
          resources: [this.bonusClaimsTable.tableArn],
        }),
      ]),
      role: seedDataRole,
    });

    // Add outputs
    new cdk.CfnOutput(this, 'BonusClaimsTableName', {
      value: this.bonusClaimsTable.tableName,
      description: 'The name of the DynamoDB table for bonus claims',
      exportName: `${this.stackName}-BonusClaimsTableName`,
    });

    new cdk.CfnOutput(this, 'BonusClaimsTableArn', {
      value: this.bonusClaimsTable.tableArn,
      description: 'The ARN of the DynamoDB table for bonus claims',
      exportName: `${this.stackName}-BonusClaimsTableArn`,
    });
  }
}