npm package: @omersalkanovic/nestjs-dynamodb
Description: NestJS DynamoDB Client - Fork 
Author: Omer Salkanovic
Latest version: 0.4.7

# NestJS DynamoDB

## Description

Opinated way to use DynamoDB with NestJS and typescript, heavily inspired by [nestjs-typed-dynamodb](https://www.npmjs.com/package/nestjs-typed-dynamodb)

## Getting Started

First install this module

`npm install @omersalkanovic/nestjs-dynamodb`

Notice that it will install [dynamodb-data-mapper-annotations](https://github.com/awslabs/dynamodb-data-mapper-js/tree/master/packages/dynamodb-data-mapper-annotations) as a dependency

## Usage

In order to create a DynamoDB connection

**app.module.ts**

```typescript
import { Module } from '@nestjs/common'
import { TypegooseModule } from 'nestjs-typed-dynamodb'
import { CatsModule } from './cat.module.ts'

@Module({
  imports: [
    DynamoDBModule.forRoot({
      AWSConfig: {
        region: 'local',
        accessKeyId: 'null',
        secretAccessKey: 'null',
      },
      dynamoDBOptions: {
        endpoint: 'localhost:8000',
        sslEnabled: false,
        region: 'local-env',
      },
    }),
    CatsModule,
  ],
})
export class ApplicationModule {}
```

To insert records to Dynamo, you first need to create your table, for this we use [dynamodb-data-mapper-annotations](https://github.com/awslabs/dynamodb-data-mapper-js/tree/master/packages/dynamodb-data-mapper-annotations) (under the hood). Every decorator in that package is exposed in this package as well **BUT CAPITALIZED** .

**cat.schema.ts**

```typescript
import {
  Attribute,
  AutoGeneratedHashKey,
  RangeKey,
  Table,
  VersionAttribute,
} from '@omersalkanovic/nestjs-dynamodb'
import * as nanoid from 'nanoid'

@Table('cat')
class Cat {
  @RangeKey({ defaultProvider: nanoid })
  id: string

  @HashKey()
  breed: string

  @Attribute()
  age: number

  @Attribute()
  alive?: boolean

  // This property will not be saved to DynamoDB.
  notPersistedToDynamoDb: string
}
```

Note: nanoid is only used a way to assign a random id, feel free to use whatever you want

**cats.service.ts**

```typescript
import { Injectable } from '@nestjs/common'
import { ReturnModel, InjectModel, OR } from '@omersalkanovic/nestjs-dynamodb'
import { Cat } from './cat.schema'
import { CatInput } from './cat.input'

const ReturnModel = ReturnModel<Cat>()

@Injectable()
export class CatsService {
  constructor(
    @InjectModel(Cat)
    private readonly catModel: typeof ReturnModel,
  ) {}

  async findAll(): Promise<Cat[]> {
    return this.catModel.find()
  }

  async findById(id: string): Promise<Cat> {
    return this.catModel.findById(id)
  }

  async create(input: CatInput): Promise<Cat> {
    return this.catModel.create(input)
  }

  async delete(input: string): Promise<DynamoDB.DeleteItemOutput> {
    return this.catModel.findByIdAndDelete(input)
  }

  async update(id: string, item: CatInput): Promise<Cat> {
    return this.catModel.findByIdAndUpdate(id, item)
  }

  async find(input: Partial<CatInput>): Promise<Cat[]> {
    return this.catModel.find(input);


  }
}
```
Now its to much easily to query through dynamoDB If you have arrays and different objects
```typescript 
  async find(input: Partial<CatInput>): Promise<Cat[]> {
    return this.catModel.find({alive: true, age: OR(19)});
    // {
    //   TableName: 'cat',
    //   ExpressionAttributeValues: {
    //     ':aliveValue': { BOOL: true },
    //     ':ageValue': { N: 19 },
    //   },
    //   FilterExpression: 'alive = :aliveValue OR age = :ageValue'
    // }

    async find(input: Partial<CatInput>): Promise<Cat[]> {
    return this.catModel.find({alive: true, age: [10, 12]});
    // {
    //   TableName: 'cat',
    //   ExpressionAttributeValues: {
    //     ':aliveValue': { BOOL: true },
    //     ':ageValue0': { N: 10 },
    //     ':ageValue1': { N: 12 },
    //   },
    //   FilterExpression: 'alive = :aliveValue AND (age = :ageValue0 OR age = :ageValue1)'
    // }
  }
```
Now you can use your service as you wish!

## Async configuration

**app.module.ts**

```typescript
import { Module } from '@nestjs/common'
import { TypegooseModule } from 'nestjs-typegoose'
import { Cats } from './cat.schema'

@Module({
  imports: [
    DynamoDBModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: async (config: ConfigService) => ({
        AWSConfig: {
          region: 'local',
          accessKeyId: 'null',
          secretAccessKey: 'null',
        },
        dynamoDBOptions: {
          endpoint: config.get<string>('DYNAMODB_URL', 'localhost:8000'),
          sslEnabled: false,
          region: 'local-env',
        },
      }),
      inject: [ConfigService],
    }),
  ],
})
export class ApplicationModule {}
```