import { Model } from "../core/Model";
import { TCache as Cache } from '../core/Cache';
import { CONSTANTS } from '../constants';
import { Join } from "../core/Join";
import { QueryBuilder } from "../core/Driver";
import { TResult } from "../core";
import { TResultDecorator } from "./decorator";
export type TCache = Cache;
export type TCacheModel = {
    provider: () => string;
    driver: (driver: "db" | "memory" | "redis") => any;
    all: () => Promise<any[]>;
    clear: () => Promise<void>;
    get: (key: string, options?: {
        namespace?: boolean;
    }) => Promise<any>;
    exists: (key: string, options?: {
        namespace?: boolean;
    }) => Promise<boolean>;
    set: (key: string, value: unknown, ms: number, options?: {
        namespace?: boolean;
    }) => Promise<void>;
    delete: (key: string, options?: {
        namespace?: boolean;
    }) => Promise<void>;
};
export type TConstant = typeof CONSTANTS;
export type TRelationOptions<K = any> = {
    name: K;
    model: new () => Model<any, any>;
    as?: string;
    localKey?: string;
    foreignKey?: string;
    freezeTable?: string;
    pivot?: string;
    query?: any;
    queryPivot?: any;
    relation?: string;
    exists?: boolean;
    notExists?: boolean;
    all?: boolean;
    trashed?: boolean;
    count?: boolean;
    oldVersion?: boolean;
    modelPivot?: new () => Model;
};
export type TRelationQueryOptions<K = any> = {
    name: K extends void ? never : K;
    model: new () => Model<any, any>;
    as?: string;
    localKey?: string;
    foreignKey?: string;
    freezeTable?: string | undefined;
    pivot?: string | undefined;
    query?: any;
    relation?: Object | undefined;
    exists?: boolean;
    all?: boolean;
    trashed?: boolean;
    count?: boolean;
    oldVersion?: boolean;
    modelPivot?: new () => Model;
};
export type TRelationShip = {
    hasOne: string;
    hasMany: string;
    belongsTo: string;
    belongsToMany: string;
};
export type TPagination<K = any> = {
    meta: {
        total: number;
        limit: number;
        count: number;
        current_page: number;
        last_page: number;
        next_page: number;
        prev_page: number;
        page: {
            prev: number;
            next: number;
            current: number;
            last: number;
        };
    };
    data: K[];
};
export type TSave = "INSERT" | "INSERT_MULTIPLE" | "INSERT_NOT_EXISTS" | "INSERT_OR_SELECT" | "UPDATE" | "UPDATE_OR_INSERT";
export type TBackup = {
    database: string;
    to?: {
        driver?: TDriver;
        host: string;
        port: number;
        username: string;
        password: string;
    };
};
export type TBackupToFile = {
    database?: string;
    filePath: string;
    table?: string;
    connection?: {
        host: string;
        port: number;
        database: string;
        username: string;
        password: string;
    };
};
export type TBackupTableToFile = {
    filePath: string;
    table: string;
    connection?: {
        host: string;
        port: number;
        database: string;
        username: string;
        password: string;
    };
};
export type TConnectionOptions = {
    [key: string]: any;
    driver?: TDriver;
    host: string;
    port: number;
    database?: string;
    username: string;
    password: string;
};
export type TPoolCallback = {
    query: (sql: string, callback: (err: any, result: any) => void) => void;
    release: () => void;
};
export type TConnectionTransaction = {
    query: (sql: string) => Promise<any[]>;
    /**
     * The 'startTransaction' method is used when need to started the transaction
     * @returns {Promise<void>}
     */
    startTransaction: () => Promise<void>;
    /**
     * The 'commit' method is used to when need to commit the transactions is successfully
     * @returns {Promise<void>}
     */
    commit: () => Promise<void>;
    /**
     * The 'rollback ' method is used to when the transaction is failed
     * @returns {Promise<void>}
     */
    rollback: () => Promise<void>;
    /**
     * The 'end ' method is used to end the transction
     * @returns {Promise<void>}
     */
    end: () => Promise<void>;
    /**
     * The 'release' method is used to release connection
     * @returns {Promise<void>}
     */
    release: () => Promise<void>;
};
export type TConnection = {
    on: (event: TPoolEvent, data: any) => void;
    query: (sql: string) => Promise<any[]>;
    queryBuilder: typeof QueryBuilder;
    startTransaction: () => Promise<void>;
    commit: () => Promise<void>;
    rollback: () => Promise<void>;
    end: () => Promise<void>;
    release: () => Promise<void>;
};
export type TPoolConnected = {
    database: () => string;
    on: (event: TPoolEvent, data: (r: any) => any) => void;
    queryBuilder: typeof QueryBuilder;
    query: (sql: string) => Promise<any[]>;
    connection: () => Promise<TConnection>;
};
export type TModelOrObject = {
    model: new () => Model<any, any>;
    alias?: string;
    key?: string;
    join?: Join;
} | (new () => Model<any, any>);
export type TCreateNewConnection = {
    on: (event: TPoolEvent, data: (r: any) => any) => void;
    query: (sql: string) => Promise<any>;
    connection: () => Promise<TConnectionTransaction>;
};
export type TOptions = {
    [key: string]: any;
    driver?: TDriver;
    host: string;
    port: number;
    database?: string;
    user: string;
    password: string;
};
export type TExecute = {
    sql: string;
    type: string;
    message?: string;
    options?: {
        [key: string]: any;
    };
};
export type TPattern = 'snake_case' | 'camelCase' | 'default';
export type TValidateSchema = null | Record<string, NumberConstructor | StringConstructor | DateConstructor | BooleanConstructor | {
    type: NumberConstructor | StringConstructor | DateConstructor | BooleanConstructor;
    require?: boolean;
    match?: RegExp;
    length?: number;
    minLength?: number;
    maxLength?: number;
    min?: number;
    max?: number;
    enum?: string[] | number[] | boolean[];
    unique?: boolean;
    json?: boolean;
    fn?: Function;
}>;
export type TValidateSchemaDecorator = NumberConstructor | StringConstructor | DateConstructor | BooleanConstructor | {
    type: NumberConstructor | StringConstructor | DateConstructor | BooleanConstructor;
    require?: boolean;
    match?: RegExp;
    length?: number;
    minLength?: number;
    maxLength?: number;
    min?: number;
    max?: number;
    enum?: string[] | number[] | boolean[];
    unique?: boolean;
    json?: boolean;
    fn?: (value: any) => string | null | Promise<string | null>;
};
export type TNonEmptyArray<T> = [T, ...T[]];
export type TGlobalSetting = {
    softDelete?: boolean;
    debug?: boolean;
    uuid?: boolean;
    timestamp?: boolean;
    logger?: {
        selected?: boolean;
        inserted?: boolean;
        updated?: boolean;
        deleted?: boolean;
    };
};
export type TOperator = {
    'eq': string;
    'notEq': string;
    'more': string;
    'less': string;
    'moreOrEq': string;
    'lessOrEq': string;
    'like': string;
    'notLike': string;
    'in': string;
    'notIn': string;
    'isNull': string;
    'isNotNull': string;
    'query': string;
    '|eq': string;
    '|notEq': string;
    '|more': string;
    '|less': string;
    '|moreOrEq': string;
    '|lessOrEq': string;
    '|like': string;
    '|notLike': string;
    '|in': string;
    '|notIn': string;
    '|isNull': string;
    '|isNotNull': string;
    '|query': string;
};
export type TPoolEvent = 'release' | 'query' | 'slowQuery' | 'select' | 'insert' | 'update' | 'delete';
export type TRawStringQuery = `$RAW:${string}`;
export type TFreezeStringQuery = `$Freeze:${string}`;
export type TOperatorQuery = `$OP:${string}`;
export type TPickColumns<T, K extends keyof T> = {
    [P in K]: T[P];
};
export type TPickRelations<T, K extends keyof T> = {
    [P in K]: T[P];
};
export type TRegistry = {
    '$save'?: Function;
    '$attach'?: Function;
    '$detach'?: Function;
};
export type TSchemaColumns<T> = TSchemaKeys<T> | `${string}.${string}` | TRawStringQuery | TFreezeStringQuery;
export type TSchemaKeys<T> = keyof {
    [K in keyof T as string extends K ? never : K]: T[K];
} extends never ? string : keyof {
    [K in keyof T as string extends K ? never : K]: T[K];
};
export type TRelationResults<T> = T extends Array<infer A> ? TRelationResults<A>[] : T extends object ? {
    [K in keyof T as K extends `$${string}` ? never : K]: TRelationResults<T[K]>;
} : T;
export type TRelationKeys<T> = {
    [K in keyof T as K extends `$${string}` ? never : K]: T[K];
} extends infer R ? keyof R extends never ? string : keyof R : string;
export type TNestedBoolean = boolean | {
    [key: string]: TNestedBoolean;
};
export type TStoreProcedure = {
    params: (string | number | boolean)[] | Record<string, string | number | boolean>;
    result: unknown;
};
export type TRemoveIndexSignature<T> = {
    [K in keyof T as string extends K ? never : number extends K ? never : K]: T[K];
};
export type TLiteralStringKeys<T> = {
    [K in keyof T]: T[K] extends string ? (string extends T[K] ? never : K) : never;
}[keyof T];
export type TLiteralEnumKeys<T> = TLiteralStringKeys<TRemoveIndexSignature<T>>;
export type TDriver = 'pg' | 'postgres' | 'mysql' | 'mysql2' | 'mariadb' | 'mssql' | 'sqlite' | 'mongodb';
export type TPoolCusterOptions = {
    writer: {
        host: string;
        user: string;
        password: string;
        database: string;
    };
    readers: {
        host: string;
        user: string;
        password: string;
        database: string;
    }[];
};
type TClusterPool = {
    pool: {
        type: string;
        node: number;
        host: string;
        port: number;
        username: string;
    };
    on: (event: TPoolEvent, data: (r: any) => any) => void;
    queryBuilder: typeof QueryBuilder;
    query: (sql: string) => Promise<any[]>;
    connection: () => Promise<TConnection>;
};
export type TPoolCusterConnected = {
    database?: () => string;
    query?: Function | null;
    queryBuilder?: QueryBuilder | null;
    masters: TClusterPool[];
    slaves: TClusterPool[];
};
export type TIsEnum<T> = string extends T ? false : number extends T ? false : boolean extends T ? false : [
    T
] extends [string | number] ? true : false;
export type TLifecycle = "beforeInsert" | "afterInsert" | "beforeUpdate" | "afterUpdate" | "beforeRemove" | "afterRemove";
export type TDeepOmit<T, Filter> = T extends infer ObjectType ? {
    [K in keyof ObjectType as K extends keyof Filter ? Filter[K] extends true ? never : K : NonNullable<ObjectType[K]> extends object ? (NonNullable<ObjectType[K]> extends Date ? K : never) : K]: K extends keyof Filter ? Filter[K] extends object ? TDeepOmit<NonNullable<ObjectType[K]>, Filter[K]> : ObjectType[K] : ObjectType[K];
} : never;
export type TDeepExpand<T> = T extends Date ? T : T extends Function ? T : T extends Model ? T : T extends (infer U)[] ? TDeepExpand<U>[] : T extends object ? {
    [K in keyof T]: TDeepExpand<T[K]>;
} : T;
export type TResultResolved<M extends Model> = (unknown extends TResult<M> ? unknown extends TResultDecorator<M> ? Record<string, any> : {} extends TResultDecorator<M> ? Record<string, any> : TResultDecorator<M> : TResult<M>);
export type TConflictKeys<R extends readonly PropertyKey[], O extends readonly PropertyKey[]> = Extract<R[number], O[number]>;
type Normalize<T> = T extends object ? ((T extends {
    select: infer S;
} ? S : {}) & (T extends {
    relations: infer R;
} ? R : {}) & (T extends {
    except: infer E;
} ? {
    _except: E;
} : {}) & Omit<T, 'select' | 'relations' | 'except'>) : {};
type IsStrict<T> = T extends true ? false : T extends object ? (T extends {
    select: any;
} ? true : T extends {
    except: any;
} ? false : (keyof Omit<T, 'relations' | 'except'> extends never ? false : true)) : false;
type RemoveUndefined<T> = T extends undefined ? never : T;
type NonObjectKeys<T> = {
    [K in keyof T]: RemoveUndefined<T[K]> extends Date ? K : RemoveUndefined<T[K]> extends object ? never : K;
}[keyof T];
type GetExceptKeys<T> = T extends {
    _except: infer E;
} ? keyof E : never;
export type TSelectionMerger<IncomingResult, S1, S2> = IncomingResult extends Date | Function ? IncomingResult : IncomingResult extends (infer U)[] ? TSelectionMerger<U, S1, S2>[] : IncomingResult extends object ? (Normalize<S1> extends infer F1 ? Normalize<S2> extends infer F2 ? (F1 & F2) extends infer Merged ? {
    [K in keyof Omit<Merged, '_except'> & keyof IncomingResult]-?: TSelectionMerger<RemoveUndefined<IncomingResult[K]>, K extends keyof F1 ? F1[K] : unknown, K extends keyof F2 ? F2[K] : unknown>;
} & ((IsStrict<S1> extends true ? true : IsStrict<S2> extends true ? true : false) extends true ? {} : {
    [K in Exclude<NonObjectKeys<IncomingResult>, GetExceptKeys<F1> | GetExceptKeys<F2>>]-?: IncomingResult[K];
}) : never : never : never) : IncomingResult;
export type TStateWhereCondition = {
    column?: string;
    operator?: string;
    value?: any;
    condition?: 'AND' | 'OR';
    nested?: TStateWhereCondition[];
};
export {};
