/* 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>;
}
Source