Untitled

 avatar
unknown
plain_text
2 months ago
3.6 kB
6
Indexable
import { Injectable } from '@nestjs/common';
import {
  EmployeeProfile,
  EmployeeProfileFields,
  NestedProjection,
  Projection,
} from './type/employee.types';
import { RSuiteLoggerService } from '@rooster-cluck-cluck/rooster-suite';
import { InjectConnection } from '@nestjs/mongoose';
import { Connection } from 'mongoose';

type EmployeeProfileDbRecord = Omit<EmployeeProfile, 'accountId'> & {
  accountId: number;
};

@Injectable()
export class EmployeeService {
  /**
   * An array of allowed fields that can be included in the employee profile projection.
   *
   * This property defines the fields that can be requested when fetching an employee's
   * profile, either as flat fields or as nested objects. The fields included are:
   *
   **/
  private allowedFields: (EmployeeProfileFields | NestedProjection)[] = [
    '_id',
    'companyId',
    'workEmail',
    { accountDetails: ['firstName', 'lastName', 'profileUrl'] },
  ];

  constructor(
    @InjectConnection() private readonly _connection: Connection,
    private readonly _rSuiteLoggerService: RSuiteLoggerService,
  ) {}

  private constructMongoProjection(
    fields: (EmployeeProfileFields | NestedProjection)[],
    parentKey = '',
  ): Record<string, 1> {
    const projection: Record<string, 1> = {};

    for (const field of fields) {
      if (typeof field === 'string') {
        projection[parentKey ? `${parentKey}.${field}` : field] = 1;
        continue;
      }

      for (const [key, nestedFields] of Object.entries(field)) {
        const nestedProjection = this.constructMongoProjection(
          nestedFields as (EmployeeProfileFields | NestedProjection)[],
          parentKey ? `${parentKey}.${key}` : key,
        );

        Object.assign(projection, nestedProjection);
      }
    }

    return projection;
  }

  /**
   * Retrieves the profile of an employee by their account ID.
   *
   * @param projection - An optional object specifying which fields to include in the response.
   * @param employeeId - The ID of the employee whose profile is to be retrieved.
   * @param token - An optional authorization token for the request.
   *
   * @returns A Promise that resolves to the EmployeeProfile object.
   *
   * @throws Error if the request to fetch the employee profile fails.
   */
  public async getEmployeeProfile(
    projection?: Projection,
    employeeId?: number,
    token?: string,
  ): Promise<EmployeeProfile> {
    this._rSuiteLoggerService.trace('Starting employee service methods: %o', {
      user: employeeId,
    });

    const projectionFields = this.constructMongoProjection(
      projection?.fields || this.allowedFields,
    );

    try {
      this._rSuiteLoggerService.trace(
        'Starting mongo method for get employee details: %o',
        {
          user: employeeId,
        },
      );

      if (!employeeId) {
        throw new Error('Employee id is required');
      }

      const response = (await this._connection
        .collection<EmployeeProfileDbRecord>('EmployeeProfile')
        .findOne(
          { accountId: employeeId },
          { projection: projectionFields },
        )) as unknown as EmployeeProfile;

      this._rSuiteLoggerService.info('Employee details get successfully: %o', {
        user: employeeId,
      });

      return response;
    } catch (error) {
      throw new Error(
        `Error fetching employee profile: ${
          error instanceof Error ? error.message : String(error)
        }`,
      );
    }
  }
}
Editor is loading...
Leave a Comment