Source

query/options.ts

/* eslint-disable @typescript-eslint/no-empty-object-type */
import {
  GroupBySelector,
  LimitSelector,
  OffsetSelector,
  OrderBySelector,
  OrderDirectionInput,
  SelectSelector,
} from "./selectors";
import { Executor } from "../interfaces";
import { Model } from "@decaf-ts/decorator-validation";
import { Condition } from "./Condition";
import { Paginatable } from "../interfaces/Paginatable";
import { Constructor } from "@decaf-ts/decoration";

type NormalizedGroupKey<M extends Model, K extends keyof M> =
  M[K] extends PropertyKey ? M[K] : PropertyKey;

type GroupByReturnValue<
  M extends Model,
  Keys extends readonly GroupBySelector<M>[],
> = Keys extends [
  infer Head extends keyof M,
  ...infer Tail extends readonly GroupBySelector<M>[]
]
  ? Record<
      NormalizedGroupKey<M, Head>,
      GroupByReturnValue<M, Tail>
    >
  : M[];

export interface StatementExecutor<M extends Model, R>
  extends Executor<R>,
    Paginatable<M, R, any> {}

export interface PreparableStatementExecutor<M extends Model, R>
  extends StatementExecutor<M, R> {
  prepare(...args: any[]): Promise<StatementExecutor<M, R>>;
}
/**
 * @summary GroupBy Option interface
 * @description Exposes the GROUP BY method and remaining options
 *
 * @interface GroupByOption
 * @memberOf module:core
 */
export interface GroupByResult<
  M extends Model,
  Keys extends readonly GroupBySelector<M>[] = readonly GroupBySelector<M>[],
> extends PreparableStatementExecutor<M, GroupByReturnValue<M, Keys>>,
    OrderByOption<M, GroupByReturnValue<M, Keys>>,
    LimitOption<M, GroupByReturnValue<M, Keys>>,
    OffsetOption<M, GroupByReturnValue<M, Keys>> {
  thenBy<Key extends GroupBySelector<M>>(
    selector: Key
  ): GroupByResult<M, [...Keys, Key]>;
}

export interface GroupByOption<M extends Model> {
  groupBy<Key extends GroupBySelector<M>>(
    selector: Key
  ): GroupByResult<M, [Key]>;
}
/**
 * @summary Offset Option interface
 * @description Exposes the OFFSET method and remaining options
 *
 * @interface GroupByOption
 * @memberOf module:core
 */
export interface OffsetOption<M extends Model, R>
  extends PreparableStatementExecutor<M, R> {
  offset(selector: OffsetSelector): PreparableStatementExecutor<M, R>;
}
/**
 * @summary Limit Option interface
 * @description Exposes the LIMIT method and remaining options
 *
 * @interface LimitOption
 * @memberOf module:core
 */
export interface LimitOption<M extends Model, R>
  extends PreparableStatementExecutor<M, R> {
  limit(selector: LimitSelector): OffsetOption<M, R>;
}
/**
 * @summary OrderBy Option interface
 * @description Exposes the ORDER BY method and remaining options
 *
 * @interface OrderByOption
 * @memberOf module:core
 */
export interface OrderByResult<M extends Model, R>
  extends LimitOption<M, R>,
    OffsetOption<M, R>,
    OrderByThenByStarterOption<M, R> {}

export interface OrderByOption<M extends Model, R>
  extends PreparableStatementExecutor<M, R> {
  orderBy(selector: OrderBySelector<M>): OrderByResult<M, R>;
  orderBy(
    attribute: keyof M,
    direction: OrderDirectionInput
  ): OrderByResult<M, R>;
}
/**
 * @summary OrderBy chaining starter interface
 * @description Exposes the thenBy methods for continuing orderBy chains
 *
 * @interface OrderByThenByStarterOption
 * @memberOf module:core
 */
export interface OrderByThenByStarterOption<M extends Model, R> {
  thenBy(selector: OrderBySelector<M>): OrderByThenByOption<M, R>;
  thenBy(
    attribute: keyof M,
    direction: OrderDirectionInput
  ): OrderByThenByOption<M, R>;
}

/**
 * @summary OrderBy chaining continuation interface
 * @description Exposes limit/offset and further thenBy chaining for multi-level sorts
 *
 * @interface OrderByThenByOption
 * @memberOf module:core
 */
export interface OrderByThenByOption<M extends Model, R>
  extends LimitOption<M, R>,
    OffsetOption<M, R>,
    OrderByThenByStarterOption<M, R> {}
/**
 * @summary Groups several order and grouping options
 *
 * @interface OrderAndGroupOption
 * @extends OrderByOption
 * @extends GroupByOption
 * @extends LimitOption
 * @extends OffsetOption
 * @memberOf module:core
 */
export interface OrderAndGroupOption<M extends Model, R>
  extends OrderByOption<M, R>,
    PreparableStatementExecutor<M, R>,
    GroupByOption<M>,
    LimitOption<M, R>,
    OffsetOption<M, R> {}
/**
 * @summary Where Option interface
 * @description Exposes the WHERE method and remaining options
 *
 * @interface WhereOption
 * @extends OrderAndGroupOption
 * @memberOf module:core
 */
export interface WhereOption<M extends Model, R>
  extends OrderAndGroupOption<M, R> {
  /**
   * @summary filter the records by a condition
   *
   * @param {Condition} condition
   * @method
   */
  where(condition: Condition<M>): OrderAndGroupOption<M, R>;
}

/**
 * @summary From Option Interface
 * @description Exposes the FROM method and remaining options
 *
 * @interface FromOption
 * @memberOf module:core
 */
export interface FromOption<M extends Model, R> {
  /**
   * @summary selects records from a table
   *
   * @param {Constructor} tableName
   * @method
   */
  from(tableName: Constructor<M> | string): WhereOption<M, R>;
}

/**
 * @summary Distinct Option Interface
 * @description Exposes the remaining options after a DISTINCT
 *
 * @interface DistinctOption
 * @extends FromOption
 * @memberOf module:core
 */
export interface DistinctOption<M extends Model, R> extends FromOption<M, R> {}

/**
 * @summary Max Option Interface
 * @description Exposes the remaining options after a MAX
 *
 * @interface MaxOption
 * @extends FromOption
 * @memberOf module:core
 */
export interface MaxOption<M extends Model, R> extends FromOption<M, R> {}

/**
 * @summary Min Option Interface
 * @description Exposes the remaining options after a MIN
 *
 * @interface MinOption
 * @extends FromOption
 * @memberOf module:core
 */
export interface MinOption<M extends Model, R> extends FromOption<M, R> {}

/**
 * @summary Count Distinct Where Option Interface
 * @description Exposes the remaining options after COUNT DISTINCT...FROM
 *
 * @interface CountDistinctWhereOption
 * @memberOf module:core
 */
export interface CountDistinctWhereOption<M extends Model>
  extends OrderAndGroupOption<M, number> {
  /**
   * @summary filter the records by a condition
   * @param {Condition} condition
   */
  where(condition: Condition<M>): CountDistinctWhereOption<M>;
}

/**
 * @summary Count Where Option Interface
 * @description Exposes the remaining options after COUNT...FROM with distinct() available
 *
 * @interface CountWhereOption
 * @memberOf module:core
 */
export interface CountWhereOption<M extends Model>
  extends OrderAndGroupOption<M, number> {
  /**
   * @summary Makes the count distinct
   * @description When chained after count(), counts only distinct values
   * @return A count distinct query builder
   */
  distinct(): CountDistinctWhereOption<M>;

  /**
   * @summary filter the records by a condition
   * @param {Condition} condition
   */
  where(condition: Condition<M>): CountWhereOption<M>;
}

/**
 * @summary Count Option Interface
 * @description Exposes the remaining options after a COUNT
 *
 * @interface CountOption
 * @memberOf module:core
 */
export interface CountOption<M extends Model> {
  /**
   * @summary Makes the count distinct
   * @description When chained after count(), counts only distinct values
   * @return A count distinct query builder
   */
  distinct(): CountDistinctOption<M>;

  /**
   * @summary selects records from a table
   * @param {Constructor} tableName
   */
  from(tableName: Constructor<M> | string): CountWhereOption<M>;
}

/**
 * @summary Count Distinct Option Interface
 * @description Exposes the remaining options after a COUNT DISTINCT
 *
 * @interface CountDistinctOption
 * @memberOf module:core
 */
export interface CountDistinctOption<M extends Model> {
  /**
   * @summary selects records from a table
   * @param {Constructor} tableName
   */
  from(tableName: Constructor<M> | string): CountWhereOption<M>;
}

/**
 * @summary Sum Option Interface
 * @description Exposes the remaining options after a SUM
 *
 * @interface SumOption
 * @extends FromOption
 * @memberOf module:core
 */
export interface SumOption<M extends Model, R> extends FromOption<M, R> {}

/**
 * @summary Avg Option Interface
 * @description Exposes the remaining options after an AVG
 *
 * @interface AvgOption
 * @extends FromOption
 * @memberOf module:core
 */
export interface AvgOption<M extends Model, R> extends FromOption<M, R> {}

/**
 * @summary Select Option Interface
 * @description Exposes the remaining options after a SELECT
 *
 * @interface SelectOption
 * @extends FromOption
 * @memberOf module:core
 */
export interface SelectOption<M extends Model, R> extends FromOption<M, R> {
  distinct<S extends SelectSelector<M>>(selector: S): DistinctOption<M, M[S][]>;

  max<S extends SelectSelector<M>>(selector: S): MaxOption<M, M[S]>;

  min<S extends SelectSelector<M>>(selector: S): MinOption<M, M[S]>;

  count<S extends SelectSelector<M>>(selector?: S): CountOption<M>;

  sum<S extends SelectSelector<M>>(selector: S): SumOption<M, number>;

  avg<S extends SelectSelector<M>>(selector: S): AvgOption<M, number>;
}

/**
 * @summary Into Option Interface
 * @description Exposes the remaining options after an INTO
 *
 * @interface IntoOption
 * @memberOf module:core
 */
export interface IntoOption<M extends Model, R> {
  values(...models: M[]): Executor<R>;

  where(condition: Condition<M>): Executor<R>;
}
/**
 * @summary Valuest Option Interface
 * @description Exposes the remaining options after a VALUES
 *
 * @interface ValuesOption
 * @memberOf module:core
 */
export interface ValuesOption<M extends Model> extends Executor<M> {}
/**
 * @summary Insert Option Interface
 * @description Exposes the remaining options after an INSERT
 *
 * @interface InsertOption
 * @memberOf module:core
 */
export interface InsertOption<M extends Model, R = void> {
  /**
   * @summary selects the table to insert records into
   *
   * @param {string | Constructor} table
   * @method
   */
  into(table: Constructor<M>): IntoOption<M, R>;
}

/**
 * @summary {@link Operator} Option Interface
 * @description Exposes the available operators for a {@link Condition}
 *
 * @interface AttributeOption
 * @memberOf module:core
 */
export interface AttributeOption<M extends Model> {
  /**
   * @summary Test equality
   *
   * @param {any} val the value to test
   * @method
   */
  eq(val: any): Condition<M>;
  /**
   * @summary Test difference
   *
   * @param {any} val the value to test
   * @method
   */
  dif(val: any): Condition<M>;
  /**
   * @summary Test greater than
   *
   * @param {any} val the value to test
   * @method
   */
  gt(val: any): Condition<M>;
  /**
   * @summary Test lower than
   *
   * @param {any} val the value to test
   * @method
   */
  lt(val: any): Condition<M>;
  /**
   * @summary Test greater or equal to
   *
   * @param {any} val the value to test
   * @method
   */
  gte(val: any): Condition<M>;
  /**
   * @summary Test lower or equal to
   *
   * @param {any} val the value to test
   * @method
   */
  lte(val: any): Condition<M>;
  /**
   * @summary Test value in a range of values
   * @param {any[]} val
   */
  in(val: any[]): Condition<M>;
  /**
   * @summary Test value is between min and max (inclusive)
   * @param {any} min the minimum value
   * @param {any} max the maximum value
   * @method
   */
  between(min: any, max: any): Condition<M>;
  /**
   * @summary Test matches {@link RegExp}
   *
   * @param {any} val the value to test
   * @method
   */
  regexp(val: string | RegExp): Condition<M>;
  /**
   * @summary Test string starts with value
   *
   * @param {string} val the prefix to test
   * @method
   */
  startsWith(val: string): Condition<M>;
  /**
   * @summary Test string ends with value
   *
   * @param {string} val the suffix to test
   * @method
   */
  endsWith(val: string): Condition<M>;
}
/**
 * @description The starting point for creating query conditions
 * @summary Exposes the available operations for building database query conditions
 * @template M - The model type this condition builder operates on
 * @interface ConditionBuilderOption
 * @memberOf module:core
 */
export interface ConditionBuilderOption<M extends Model> {
  attribute(attr: keyof M): AttributeOption<M>;
  attr(attr: keyof M): AttributeOption<M>;
}