All files / repositories imageRepository.ts

67.5% Statements 27/40
100% Branches 1/1
80% Functions 4/5
67.5% Lines 27/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 105 106 107 108 109 110 111 1122x 2x                 2x 2x 2x     2x   2x         2x       2x 2x 2x       1x 1x         1x 1x               1x 1x                         1x       1x 1x         2x 2x     2x         2x   2x   2x 2x                                                    
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import {
  DynamoDBDocumentClient,
  PutCommand,
  GetCommand,
  DeleteCommand,
  UpdateCommand,
} from '@aws-sdk/lib-dynamodb';
import { IImageRepository } from './imageRepository.interface';
import { ImageMetadata } from '../models/imageMetadata.model';
import { config } from '../config/env';
import { InternalError } from '../common/errors';
import { getLogger } from '../common/logger';
import { ImageMetadataUpdate } from '../models/imageMetadataUpdate.model';
 
const logger = getLogger('ImageRepository');
 
export class ImageRepository implements IImageRepository {
  private docClient: DynamoDBDocumentClient;
  private tableName: string;
 
  constructor() {
    logger.info('ImageRepository config', {
      awsRegion: config.awsRegion,
      tableName: config.dynamoTableName,
    });
    const client = new DynamoDBClient({ region: config.awsRegion });
    this.docClient = DynamoDBDocumentClient.from(client);
    this.tableName = config.dynamoTableName;
  }
 
  async save(metadata: ImageMetadata): Promise<void> {
    try {
      const command = new PutCommand({
        TableName: this.tableName,
        Item: metadata,
      });
 
      await this.docClient.send(command);
      logger.info(`Metadata saved: ${metadata.imageId}`);
    } catch (error) {
      logger.error(`Repository save error: ${(error as Error).message}`);
      throw new InternalError('Failed to save image metadata');
    }
  }
 
  async update(metadata: ImageMetadataUpdate): Promise<void> {
    try {
      const command = new UpdateCommand({
        TableName: this.tableName,
        Key: { imageId: metadata.imageId },
        UpdateExpression: 'SET #url = :url, #status = :status',
        ExpressionAttributeNames: {
          '#url': 'url',
          '#status': 'status',
        },
        ExpressionAttributeValues: {
          ':url': metadata.url,
          ':status': metadata.status,
        },
      });
      await this.docClient.send(command);
 
      logger.info(`Metadata updated: ${metadata.imageId}`);
    } catch (error) {
      logger.error(`Repository update error: ${(error as Error).message}`);
      throw new InternalError('Failed to update image metadata');
    }
  }
 
  async findById(imageId: string): Promise<ImageMetadata | null> {
    try {
      logger.info(
        `Querying DynamoDB: Table=${this.tableName}, Key=${JSON.stringify({ imageId })}`
      );
      const command = new GetCommand({
        TableName: this.tableName,
        Key: { imageId },
      });
 
      const response = await this.docClient.send(command);
 
      logger.info(`DynamoDB response success`);
 
      if (!response.Item) {
        return null;
      }
 
      logger.info(`Metadata retrieved: ${imageId}`);
      return response.Item as ImageMetadata;
    } catch (error) {
      logger.error(`Repository findById error: ${(error as Error).message}`);
      throw new InternalError('Failed to retrieve image metadata');
    }
  }
 
  async delete(imageId: string): Promise<void> {
    try {
      const command = new DeleteCommand({
        TableName: this.tableName,
        Key: { imageId },
      });
 
      await this.docClient.send(command);
      logger.info(`Metadata deleted: ${imageId}`);
    } catch (error) {
      logger.error(`Repository delete error: ${(error as Error).message}`);
      throw new InternalError('Failed to delete image metadata');
    }
  }
}