File

apps/recallassess/recallassess-api/src/api/shared/services/base.service.ts

Description

Base service for client-side API services Provides common utility methods without enforcing rigid structure Services can extend this to access helpers while maintaining flexibility

Index

Properties
Methods

Methods

Protected buildCompanyWhere
buildCompanyWhere(companyId: number, additionalWhere?: Record)

Build base WHERE clause with company scope Ensures all queries are scoped to the user's company

Parameters :
Name Type Optional Description
companyId number No
  • Company ID to scope queries to
additionalWhere Record<string | any> Yes
  • Additional where conditions to merge
Returns : Record<string, any>

Complete where clause object

Protected buildSearchWhere
buildSearchWhere(searchFields: string[], searchQuery?: string)

Build a WHERE clause for search functionality Creates OR conditions for multiple fields

Parameters :
Name Type Optional Description
searchFields string[] No
  • Array of field names to search in
searchQuery string Yes
  • Search query string
Returns : [] | undefined

Array of search conditions or undefined if no query

Protected Async findByIdWithCompanyScope
findByIdWithCompanyScope(entityName: string, entityId: number, companyId: number)

Find entity by ID with company scope verification Common pattern: get entity and ensure it belongs to the company

Parameters :
Name Type Optional Description
entityName string No
  • Prisma model name
entityId number No
  • Entity ID
companyId number No
  • Company ID to verify ownership
Returns : Promise<any | null>

Entity if found and belongs to company, null otherwise

Protected getRepo
getRepo(repoName: string)

Get a Prisma repository (table) dynamically Useful for generic operations across different entities

Parameters :
Name Type Optional Description
repoName string No
  • The name of the Prisma repository (table)
Returns : any

The Prisma repository instance

Protected toDto
toDto(entity: any, dtoClass: unknown)
Type parameters :
  • TDto

Transform database entity to DTO using class-transformer

Parameters :
Name Type Optional Description
entity any No
  • Raw database entity
dtoClass unknown No
  • DTO class constructor
Returns : TDto

Transformed DTO instance

Protected toDtoArray
toDtoArray(entities: any[], dtoClass: unknown)
Type parameters :
  • TDto

Transform array of database entities to DTOs

Parameters :
Name Type Optional Description
entities any[] No
  • Array of raw database entities
dtoClass unknown No
  • DTO class constructor
Returns : TDto[]

Array of transformed DTO instances

Protected Async verifyCompanyOwnership
verifyCompanyOwnership(entityName: string, entityId: number, companyId: number)

Verify that an entity belongs to a specific company Common security check to prevent cross-company data access

Parameters :
Name Type Optional Description
entityName string No
  • Prisma model name (e.g., 'participant', 'participantGroup')
entityId number No
  • Entity ID to check
companyId number No
  • Company ID to verify ownership
Returns : Promise<boolean>

True if entity belongs to company, false otherwise

Properties

Protected Readonly prisma
Type : BNestPrismaService
Decorators :
@Inject()
import { bnestPlainToDto, bnestPlainToDtoArray } from "@bish-nest/core";
import { BNestPrismaService } from "@bish-nest/core/services";
import { Inject, Injectable } from "@nestjs/common";

/**
 * Base service for client-side API services
 * Provides common utility methods without enforcing rigid structure
 * Services can extend this to access helpers while maintaining flexibility
 */
@Injectable()
export abstract class CLBaseService {
  @Inject() protected readonly prisma!: BNestPrismaService;

  /**
   * Transform database entity to DTO using class-transformer
   * @param entity - Raw database entity
   * @param dtoClass - DTO class constructor
   * @returns Transformed DTO instance
   */
  protected toDto<TDto>(entity: any, dtoClass: new () => TDto): TDto {
    return bnestPlainToDto(entity, dtoClass);
  }

  /**
   * Transform array of database entities to DTOs
   * @param entities - Array of raw database entities
   * @param dtoClass - DTO class constructor
   * @returns Array of transformed DTO instances
   */
  protected toDtoArray<TDto>(entities: any[], dtoClass: new () => TDto): TDto[] {
    return bnestPlainToDtoArray(entities, dtoClass);
  }

  /**
   * Verify that an entity belongs to a specific company
   * Common security check to prevent cross-company data access
   * @param entityName - Prisma model name (e.g., 'participant', 'participantGroup')
   * @param entityId - Entity ID to check
   * @param companyId - Company ID to verify ownership
   * @returns True if entity belongs to company, false otherwise
   */
  protected async verifyCompanyOwnership(
    entityName: string,
    entityId: number,
    companyId: number,
  ): Promise<boolean> {
    const repo = this.getRepo(entityName);
    const entity = await repo.findFirst({
      where: {
        id: entityId,
        company_id: companyId,
      },
    });
    return !!entity;
  }

  /**
   * Build a WHERE clause for search functionality
   * Creates OR conditions for multiple fields
   * @param searchFields - Array of field names to search in
   * @param searchQuery - Search query string
   * @returns Array of search conditions or undefined if no query
   */
  protected buildSearchWhere(searchFields: string[], searchQuery?: string): any[] | undefined {
    if (!searchQuery?.trim()) {
      return undefined;
    }

    const trimmedQuery = searchQuery.trim();
    return searchFields.map((field) => ({
      [field]: { contains: trimmedQuery, mode: "insensitive" },
    }));
  }

  /**
   * Build base WHERE clause with company scope
   * Ensures all queries are scoped to the user's company
   * @param companyId - Company ID to scope queries to
   * @param additionalWhere - Additional where conditions to merge
   * @returns Complete where clause object
   */
  protected buildCompanyWhere(companyId: number, additionalWhere?: Record<string, any>): Record<string, any> {
    return {
      company_id: companyId,
      ...additionalWhere,
    };
  }

  /**
   * Get a Prisma repository (table) dynamically
   * Useful for generic operations across different entities
   * @param repoName - The name of the Prisma repository (table)
   * @returns The Prisma repository instance
   * @throws Error if repository doesn't exist
   */
  protected getRepo(repoName: string): any {
    if (!(repoName in this.prisma.client)) {
      throw new Error(`Repository "${repoName}" does not exist in Prisma Client.`);
    }
    return (this.prisma.client as any)[repoName];
  }

  /**
   * Find entity by ID with company scope verification
   * Common pattern: get entity and ensure it belongs to the company
   * @param entityName - Prisma model name
   * @param entityId - Entity ID
   * @param companyId - Company ID to verify ownership
   * @returns Entity if found and belongs to company, null otherwise
   */
  protected async findByIdWithCompanyScope(
    entityName: string,
    entityId: number,
    companyId: number,
  ): Promise<any | null> {
    const repo = this.getRepo(entityName);
    return await repo.findFirst({
      where: {
        id: entityId,
        company_id: companyId,
      },
    });
  }
}

results matching ""

    No results matching ""