dashpresshq/dashpress

View on GitHub
src/backend/data/data-access/_Base.ts

Summary

Maintainability
B
4 hrs
Test Coverage
D
69%
import type { IColumnFilterBag, QueryFilterSchema } from "@/shared/types/data";
import { DATE_FILTER_VALUE, FilterOperators } from "@/shared/types/data";

import type { IPaginationFilters } from "../types";
import { relativeDateNotationToActualDate } from "./time.constants";
import type { QueryOperationImplementation } from "./types";
import { QueryOperators } from "./types";

export abstract class BaseDataAccessService<T> {
  abstract queryOperationImplementation: QueryOperationImplementation<T>;

  abstract count(
    entity: string,
    queryFilter: QueryFilterSchema
  ): Promise<number>;

  abstract list(
    entity: string,
    select: string[],
    queryFilter: QueryFilterSchema,
    dataFetchingModifiers: IPaginationFilters
  ): Promise<unknown[]>;

  abstract read<K>(
    entity: string,
    select: string[],
    query: Record<string, unknown>
  ): Promise<K>;

  abstract create(
    entity: string,
    data: Record<string, unknown>,
    primaryField: string
  ): Promise<string | number>;

  abstract update(
    entity: string,
    query: Record<string, unknown>,
    data: Record<string, unknown>
  ): Promise<void>;

  abstract delete(
    entity: string,
    query: Record<string, unknown>
  ): Promise<void>;

  filterOperatorToQuery(
    query: T,
    column: string,
    { operator, value, value2 }: IColumnFilterBag<unknown>,
    groupOperator: "and" | "or"
  ): T {
    if (!operator || !column) {
      return query;
    }

    if (
      operator !== FilterOperators.IS_NULL &&
      operator !== FilterOperators.IS_NOT_NULL &&
      !value
    ) {
      return query;
    }

    const operatorConfig = this.queryOperationImplementation[groupOperator];

    switch (operator) {
      case FilterOperators.IS_NULL:
        return operatorConfig[QueryOperators.IS_NULL](query, column, value);

      case FilterOperators.IS_NOT_NULL:
        return operatorConfig[QueryOperators.IS_NOT_NULL](query, column, value);

      case FilterOperators.EQUAL_TO:
        return operatorConfig[QueryOperators.EQUAL_TO](query, column, value);

      case FilterOperators.LESS_THAN:
        return operatorConfig[QueryOperators.LESS_THAN](query, column, value);

      case FilterOperators.GREATER_THAN:
        return operatorConfig[QueryOperators.GREATER_THAN](
          query,
          column,
          value
        );

      case FilterOperators.CONTAINS:
        return operatorConfig[QueryOperators.CONTAINS](query, column, value);

      case FilterOperators.IN:
        return operatorConfig[QueryOperators.IN](query, column, value);

      case FilterOperators.NOT_IN:
        return operatorConfig[QueryOperators.NOT_IN](
          query,
          column,
          value as string[]
        );

      case FilterOperators.NOT_EQUAL:
        return operatorConfig[QueryOperators.NOT_EQUAL](query, column, value);

      case FilterOperators.BETWEEN:
        if (!value2) {
          return query;
        }
        return operatorConfig[QueryOperators.BETWEEN](query, column, [
          value,
          value2,
        ]);

      case FilterOperators.DATE: {
        const firstTime = relativeDateNotationToActualDate(
          (value as string) || DATE_FILTER_VALUE.BEGINNING_OF_TIME_VALUE
        );
        const secondTime = relativeDateNotationToActualDate(
          (value2 as string) || DATE_FILTER_VALUE.NOW
        );
        const timeBetween: [Date, Date] =
          firstTime.getTime() < secondTime.getTime()
            ? [firstTime, secondTime]
            : [secondTime, firstTime];
        return operatorConfig[QueryOperators.BETWEEN](
          query,
          column,
          timeBetween
        );
      }
    }
  }
}