import "reflect-metadata";
import { DB } from "./DB";
import { AbstractModel } from "./Abstracts/AbstractModel";
import { Blueprint } from "./Blueprint";
import { JoinModel } from "./JoinModel";
import { CONSTANTS } from "../constants";
import type { T } from "./UtilityTypes";
import type { TRelationOptions, TValidateSchema, TGlobalSetting, TPattern, TRelationQueryOptions, TModelOrObject, TRelationKeys, TLifecycle, TCacheModel, TRawStringQuery } from "../types";
import { Join } from "./Join";
/**
 *
 * The 'Model' class is a representation of a database table
 * @generic {Type} TS
 * @generic {Type} TR
 * @example
 * import { Model, Blueprint, type T } from 'tspace-mysql'
 *
 * const schema = {
 *   id    : new Blueprint().int().primary().autoIncrement(),
 *   uuid  : new Blueprint().varchar(50).null(),
 *   email : new Blueprint().varchar(50).null(),
 *   name  : new Blueprint().varchar(255).null(),
 * }
 *
 * type TS = T.Schema<typeof Schema>
 *
 * class User extends Model<TS> {
 *  boot() {
 *   this.useSchema(schema)
 *  }
 * }
 *
 * const users = await new User().findMany()
 * console.log(users)
 */
declare class Model<TS extends Record<string, any> = any, TR = unknown> extends AbstractModel {
    constructor();
    /**
     * The 'global' method is used setting global variables in models.
     * @static
     * @param {GlobalSetting} settings
     * @example
     * Model.global({
     *   softDelete : true,
     *   uuid       : true,
     *   timestamp  : true,
     *   debug      : true
     *   logger     : {
     *       selected : true,
     *       inserted : true,
     *       updated  : true,
     *       deleted  : true
     *   },
     * })
     * @returns {void} void
     */
    static global(settings: TGlobalSetting): void;
    /**
     * The 'table' method is used get table name.
     * @static
     * @returns {string} name of the table
     */
    static get table(): string | null;
    /**
     * The 'formatPattern' method is used to change the format of the pattern.
     * @param {object} data { data , pattern }
     * @property {Record | string} data
     * @property {string} parttern
     * @returns {Record | string} T
     */
    static formatPattern<T extends Record<string, any> | string>({ data, pattern, }: {
        data: T;
        pattern: TPattern;
    }): T;
    /**
     * The 'instance' method is used get instance.
     * @override
     * @static
     * @returns {Model} instance of the Model
     */
    static get instance(): Model;
    /**
     * The 'query' method is used to return instance
     * @static
     * @example
     * const user = await User.query().where('id',1).findOne();
     * console.log(user);
     */
    static query<T>(this: new () => T): T;
    /**
     *
     * The 'find' method is used to retrieve a single record from a database table by its primary key.
     *
     * It allows you to retrieve a single record from a database table that meets the specified criteria.
     * @type     {?object}  options
     * @property {?object} options.select
     * @property {?object} options.except
     * @property {?object[]} options.orderBy
     * @property {?string[]} options.groupBy
     * @property {?string} options.having
     * @property {?number} options.limit
     * @property {?number} options.offset
     * @property {?object} options.where
     * @property {?string[]} options.whereRaw
     * @property {?object} options.whereQuery
     * @property {?{condition,callback}} options.when
     * @property {?{localKey , referenceKey}[]} options.join
     * @property {?{localKey , referenceKey}[]} options.rightJoin
     * @property {?{localKey , referenceKey}[]} options.leftJoin
     * @property {?string[]} options.relations
     * @property {string[]} options.relationExists
     * @property {?{condition,callback}} options.relationQuery
     * @property {?boolean} options.debug
     * @returns {promise<object>[]}
     *
     * @example
     * import { User } from '../Models/User'
     *
     * const users = await User.find({
     *       select : { id: true, name: true },
     *       where : {
     *           id: 1
     *       }
     *   })
     *
     */
    static find<Self extends Model, M extends Model = Self, S extends T.SelectOptions<M> | undefined = undefined, SR extends T.RelationOptions<M> | undefined = undefined, E extends T.ExceptOptions<M> | undefined = undefined, SRS extends Record<string, TRawStringQuery> | undefined = undefined, G extends Record<string, T.RepositoryGenericTypeOptions> | undefined = {}>(this: new () => Self, primaryKey: number | string, options?: T.RepositoryOptions<M, S, SR, E, SRS, G>): Promise<T.ResultFiltered<M, S, SR, E, SRS, G> | null>;
    /**
     *
     * The 'findOne' method is used to retrieve the get record that matches the query conditions.
     *
     * It allows you to retrieve a single record from a database table that meets the specified criteria.
     * @type     {?object}  options
     * @property {?object} options.select
     * @property {?object} options.except
     * @property {?object[]} options.orderBy
     * @property {?string[]} options.groupBy
     * @property {?string} options.having
     * @property {?number} options.limit
     * @property {?number} options.offset
     * @property {?object} options.where
     * @property {?string[]} options.whereRaw
     * @property {?object} options.whereQuery
     * @property {?{condition,callback}} options.when
     * @property {?{localKey , referenceKey}[]} options.join
     * @property {?{localKey , referenceKey}[]} options.rightJoin
     * @property {?{localKey , referenceKey}[]} options.leftJoin
     * @property {?string[]} options.relations
     * @property {string[]} options.relationExists
     * @property {?{condition,callback}} options.relationQuery
     * @property {?boolean} options.debug
     * @returns {promise<object>[]}
     *
     * @example
     * import { User } from '../Models/User'
     *
     * const users = await User.findOne({
     *       select : { id: true, name: true },
     *       where : {
     *           id: 1
     *       }
     *   })
     *
     */
    static findOne<Self extends Model, M extends Model = Self, S extends T.SelectOptions<M> | undefined = undefined, SR extends T.RelationOptions<M> | undefined = undefined, E extends T.ExceptOptions<M> | undefined = undefined, SRS extends Record<string, TRawStringQuery> | undefined = undefined, G extends Record<string, T.RepositoryGenericTypeOptions> | undefined = {}>(this: new () => Self, options?: T.RepositoryOptions<M, S, SR, E, SRS, G>): Promise<T.ResultFiltered<M, S, SR, E, SRS, G> | null>;
    /**
     *
     * The 'findMany' method is used to retrieve the get record that matches the query conditions.
     *
     * It allows you to retrieve a single record from a database table that meets the specified criteria.
     * @type     {?object}  options
     * @property {?object} options.select
     * @property {?object} options.except
     * @property {?object[]} options.orderBy
     * @property {?string[]} options.groupBy
     * @property {?string} options.having
     * @property {?number} options.limit
     * @property {?number} options.offset
     * @property {?object} options.where
     * @property {?string[]} options.whereRaw
     * @property {?object} options.whereQuery
     * @property {?{condition,callback}} options.when
     * @property {?{localKey , referenceKey}[]} options.join
     * @property {?{localKey , referenceKey}[]} options.rightJoin
     * @property {?{localKey , referenceKey}[]} options.leftJoin
     * @property {?string[]} options.relations
     * @property {string[]} options.relationExists
     * @property {?{condition,callback}} options.relationQuery
     * @property {?boolean} options.debug
     * @returns {promise<object>[]}
     *
     * @example
     * import { User } from '../Models/User'
     *
     * const users = await User.findMany({
     *       select : { id: true, name: true },
     *       where : {
     *           id: 1
     *       }
     *   })
     *
     */
    static findMany<Self extends Model, M extends Model = Self, S extends T.SelectOptions<M> | undefined = undefined, SR extends T.RelationOptions<M> | undefined = undefined, E extends T.ExceptOptions<M> | undefined = undefined, SRS extends Record<string, TRawStringQuery> | undefined = undefined, G extends Record<string, T.RepositoryGenericTypeOptions> | undefined = {}>(this: new () => Self, options?: T.RepositoryOptions<M, S, SR, E, SRS, G>): Promise<T.ResultFiltered<M, S, SR, E, SRS, G>[]>;
    /**
     *
     * The 'paginate' method is used to perform pagination on a set of database query results obtained through the Query Builder.
     *
     * It allows you to split a large set of query results into smaller, more manageable pages,
     * making it easier to display data in a web application and improve user experience.
     * @type     {?object}  options
     * @property {?object} options.select
     * @property {?object} options.except
     * @property {?object[]} options.orderBy
     * @property {?string[]} options.groupBy
     * @property {?string} options.having
     * @property {?number} options.limit
     * @property {?number} options.offset
     * @property {?object} options.where
     * @property {?string[]} options.whereRaw
     * @property {?object} options.whereQuery
     * @property {?{condition,callback}} options.when
     * @property {?{localKey , referenceKey}[]} options.join
     * @property {?{localKey , referenceKey}[]} options.rightJoin
     * @property {?{localKey , referenceKey}[]} options.leftJoin
     * @property {?string[]} options.relations
     * @property {string[]} options.relationExists
     * @property {?{condition,callback}} options.relationQuery
     * @property {?boolean} options.debug
     * @property {?number} options.page
     * @returns {promise<{ meta , data[]}>}
     *
     * @example
     * import { User } from '../Models/User'
     *
     *  const users = await User.paginate({
     *       limit:15,
     *       page: 1,
     *       select : { id: true, name: true },
     *       where : {
     *           id: 1
     *       }
     *   })
     */
    static paginate<Self extends Model, M extends Model = Self, S extends T.SelectOptions<M> | undefined = undefined, SR extends T.RelationOptions<M> | undefined = undefined, E extends T.ExceptOptions<M> | undefined = undefined, SRS extends Record<string, TRawStringQuery> | undefined = undefined, G extends Record<string, T.RepositoryGenericTypeOptions> | undefined = {}>(this: new () => Self, options?: Omit<Partial<T.RepositoryOptions<M, S, SR, E, SRS, G>> & {
        page?: number;
    }, 'offset'>): Promise<T.PaginateResultFiltered<M, S, SR, E, SRS, G>>;
    /**
     * The 'exists' method is used to determine if any records exist in the database table that match the query conditions.
     *
     * It returns a boolean value indicating whether there are any matching records.
     * @type     {?object}  options
     * @property {?object} options.select
     * @property {?object} options.except
     * @property {?object[]} options.orderBy
     * @property {?string[]} options.groupBy
     * @property {?string} options.having
     * @property {?number} options.limit
     * @property {?number} options.offset
     * @property {?object} options.where
     * @property {?string[]} options.whereRaw
     * @property {?object} options.whereQuery
     * @property {?{condition,callback}} options.when
     * @property {?{localKey , referenceKey}[]} options.join
     * @property {?{localKey , referenceKey}[]} options.rightJoin
     * @property {?{localKey , referenceKey}[]} options.leftJoin
     * @property {?boolean} options.debug
     * @property {?number} options.page
     *
     * @example
     *  import { User } from '../Models/User'
     *
     *  const users = await User.exists({
     *       where : {
     *           id: 1
     *       }
     *   })
     *
     */
    static exists<Self extends Model, M extends Model = Self>(this: new () => Self, options: Partial<Omit<T.RepositoryOptions<M>, "relations" | "relationQuery">>): Promise<boolean>;
    /**
     * The 'toQuery' method is used to retrieve the raw SQL query that would be executed by a query builder instance without actually executing it.
     *
     * This method is particularly useful for debugging and understanding the SQL queries generated by your application.
     * @type     {?object}  options
     * @property {?object} options.select
     * @property {?object} options.except
     * @property {?object[]} options.orderBy
     * @property {?string[]} options.groupBy
     * @property {?string} options.having
     * @property {?number} options.limit
     * @property {?number} options.offset
     * @property {?object} options.where
     * @property {?string[]} options.whereRaw
     * @property {?object} options.whereQuery
     * @property {?{condition,callback}} options.when
     * @property {?{localKey , referenceKey}[]} options.join
     * @property {?{localKey , referenceKey}[]} options.rightJoin
     * @property {?{localKey , referenceKey}[]} options.leftJoin
     * @property {?boolean} options.debug
     * @property {?number} options.page
     *
     * @example
     *  import { User } from '../Models/User'
     *
     *  const users = await User.exists({
     *       where : {
     *           id: 1
     *       }
     *   })
     *
     */
    static toQuery<Self extends Model, M extends Model = Self>(this: new () => Self, options: Partial<Omit<T.RepositoryOptions<M>, "relations" | "relationQuery">>): string;
    /**
     * The 'create' method is used to insert a new record into a database table associated.
     *
     * It simplifies the process of creating and inserting records.
     * @type     {object}  options
     * @property {object} options.data
     * @property {?boolean} options.debug
     * @property {?transaction} options.transaction
     * @return {promise<T.Result<M>>}
     */
    static create<Self extends Model, M extends Model = Self, NR extends boolean | undefined = false>(this: new () => Self, options: T.RepositoryCreate<M, NR>): Promise<NR extends true ? undefined : T.Result<M>>;
    /**
     * The 'createMany' method is used to insert a new records into a database table associated.
     *
     * It simplifies the process of creating and inserting records with an array.
     * @type     {object}  options
     * @property {object[]} options.data
     * @property {?boolean} options.debug
     * @property {?transaction} options.transaction
     * @return {promise<TS[]>}
     */
    static createMany<Self extends Model, M extends Model = Self, NR extends boolean | undefined = false>(this: new () => Self, options: T.RepositoryCreateMultiple<M, NR>): Promise<NR extends true ? undefined : T.Result<M>[]>;
    /**
     *
     * The 'createOrUpdate' method allows you to update an existing record in a database table if it exists or create a new record if it does not exist.
     *
     * This method is particularly useful when you want to update a record based on certain conditions and,
     * if the record matching those conditions doesn't exist, create a new one with the provided data.
     * @type     {object}  options
     * @property {object} options.data
     * @property {object} options.where
     * @property {?boolean} options.debug
     * @return {promise<NR extends true ? undefined : T.Result<M>[]>}
     */
    static createOrUpdate<Self extends Model, M extends Model = Self, NR extends boolean | undefined = false>(this: new () => Self, options: T.RepositoryCreateOrThings<M, NR>): Promise<NR extends true ? undefined : T.Result<M>[]>;
    /**
     * The 'createNotExists' method to insert data into a database table while ignoring any duplicate key constraint violations.
     *
     * This method is particularly useful when you want to insert records into a table and ensure that duplicates are not inserted,
     * but without raising an error or exception if duplicates are encountered.
     *
     * @type     {object}  options
     * @property {object} options.data
     * @property {object} options.where
     * @property {?boolean} options.debug
     * @property {?transaction} options.transaction
     * @return {promise<T | null>}
     */
    static createNotExists<Self extends Model, M extends Model = Self, NR extends boolean | undefined = false>(this: new () => Self, options: T.RepositoryCreateOrThings<M, NR>): Promise<NR extends true ? undefined : T.Result<M> | null>;
    /**
     *
     * The 'createOrSelect' method to insert data into a database table while select any duplicate key constraint violations.
     *
     * This method is particularly useful when you want to insert records into a table and ensure that duplicates are not inserted,
     * but if exists should be returns a result.
     * @type     {object}  options
     * @property {object} options.data
     * @property {object} options.where
     * @property {?boolean} options.debug
     * @return {promise<T.Result<M>>}
     */
    static createOrSelect<Self extends Model, M extends Model = Self, NR extends boolean | undefined = false>(this: new () => Self, options: T.RepositoryCreateOrThings<M, NR>): Promise<NR extends true ? undefined : T.Result<M> | null>;
    /**
     * The 'update' method is used to update existing records in a database table that are associated.
     *
     * It simplifies the process of updating records by allowing you to specify the values to be updated using a single call.
     *
     * It allows you to remove one record that match certain criteria.
     * @type     {object} options
     * @property {object} options.data
     * @property {object} options.where
     * @property {?boolean} options.debug
     * @property {?transaction} options.transaction
     * @return {promise< NR extends true ? undefined : T.Result<M> | null>}
     */
    static update<Self extends Model, M extends Model = Self, NR extends boolean | undefined = false>(this: new () => Self, options: T.RepositoryUpdate<M, NR>): Promise<NR extends true ? undefined : T.Result<M> | null>;
    /**
     * The 'updateMany' method is used to update existing records in a database table that are associated.
     *
     * It simplifies the process of updating records by allowing you to specify the values to be updated using a single call.
     *
     * It allows you to remove more records that match certain criteria.
     * @type     {object} options
     * @property {object} options.data
     * @property {object} options.where
     * @property {?boolean} options.debug
     * @property {?transaction} options.transaction
     * @return {promise<T.Result<M>[]>}
     */
    static updateMany<Self extends Model, M extends Model = Self, NR extends boolean | undefined = false>(this: new () => Self, options: T.RepositoryUpdate<M, NR>): Promise<NR extends true ? undefined : T.Result<M>[]>;
    /**
     * The 'cache' method is used get the functions from the Cache
     * @returns {TCacheModel} cache
     */
    static get cache(): TCacheModel;
    /**
     *  The 'boot' method is a special method that you can define within a model.
     *  @example
     *  class User extends Model {
     *     boot() {
     *       this.useUUID()
     *       this.usePrimaryKey('id')
     *       this.useTimestamp()
     *       this.useSoftDelete()
     *     }
     *  }
     * @returns {void} void
     */
    protected boot(): void;
    /**
     * The 'globalScope' method is a feature that allows you to apply query constraints to all queries for a given model.
     *
     * Suported only methods -> select , except , where , orderBy, GroupBy , limit and offset
     * @example
     *  class User extends Model {
     *     boot() {
     *      super()
     *      this.globalScope(query => {
     *           return query.where('id' , '>' , 10)
     *      })
     *   }
     *  }
     * @returns {void} void
     */
    protected globalScope<M extends Model>(callback: (query: M) => M): this;
    /**
     * The 'useGlobalScope' method is a feature that allows you to apply query constraints to all queries for a given model.
     *
     * Suported only methods -> select , except , where , orderBy, GroupBy , limit and offset
     *
     * @example
     *  class User extends Model {
     *     boot() {
     *      super()
     *      this.useGlobalScope(query => {
     *           return query.where('id' , '>' , 10)
     *      })
     *   }
     *  }
     * @returns {void} void
     */
    protected useGlobalScope<M extends Model>(callback: (query: M) => M): this;
    /**
     * The "useObserve" method is used to pattern refers to a way of handling model events using observer classes.
     * Model events are triggered when certain actions occur on models,
     * such as creating, updating, deleting, or saving a record.
     *
     * Observers are used to encapsulate the event-handling logic for these events,
     * keeping the logic separate from the model itself and promoting cleaner, more maintainable code.
     * @param {Function} observer
     * @returns this
     * @example
     *
     * class UserObserve {
     *    public selected(results : unknown) {
     *       console.log({ results , selected : true })
     *    }
     *
     *    public created(results : unknown) {
     *       console.log({ results , created : true })
     *    }
     *
     *    public updated(results : unknown) {
     *       console.log({ results ,updated : true })
     *    }
     *
     *    public deleted(results : unknown) {
     *       console.log({ results ,deleted : true })
     *    }
     *   }
     *
     *   class User extends Model {
     *      boot() {
     *          super()
     *          this.useObserver(UserObserve)
     *      }
     *   }
     */
    protected useObserver(observer: new () => {
        selected: Function;
        created: Function;
        updated: Function;
        deleted: Function;
    }): this;
    /**
     * The "useLogger" method is used to keeping query data and changed in models.
     *
     * @type     {object}  options
     * @property {boolean} options.selected - default is false
     * @property {boolean} options.inserted - default is true
     * @property {boolean} options.updated  - default is true
     * @property {boolean} options.deleted  - default is true
     * @example
     * class User extends Model {
     *     boot() {
     *        this.useLogger({
     *          selected : true,
     *          inserted : true,
     *          updated  : true,
     *          deleted  : true,
     *       })
     *   }
     * }
     * @returns {this} this
     */
    protected useLogger({ selected, inserted, updated, deleted, }?: {
        selected?: boolean | undefined;
        inserted?: boolean | undefined;
        updated?: boolean | undefined;
        deleted?: boolean | undefined;
    }): this;
    /**
     * The "useSchema" method is used to define the schema.
     *
     * It's automatically create, called when not exists table or columns.
     * @param {object} schema using Blueprint for schema
     * @example
     * import { Blueprint } from 'tspace-mysql';
     * class User extends Model {
     *     boot() {
     *        this.useSchema ({
     *            id          : new Blueprint().int().notNull().primary().autoIncrement(),
     *            uuid        : new Blueprint().varchar(50).null(),
     *            email       : new Blueprint().varchar(50).null(),
     *            name        : new Blueprint().varchar(255).null(),
     *            created_at  : new Blueprint().timestamp().null(),
     *            updated_at  : new Blueprint().timestamp().null()
     *         })
     *     }
     * }
     * @returns {this} this
     */
    protected useSchema(schema: Record<string, Blueprint>): this;
    /**
     * The "useTransform " method is used to define value transformers for model columns..
     *
     * Each transformer defines how a value is converted:
     * - `to`   : before persisting to the database
     * - `from` : after retrieving from the database
     *
     * Transformers can be synchronous or asynchronous.
     *
     * @param {object} transforms
     * @example
     * import { Blueprint } from 'tspace-mysql';
     * class User extends Model {
     *     boot() {
     *        this.useTransform({
     *            name : {
     *              to   : async (v) => `${v}-> transform@before`,
     *              from : async (v) => `${v}-> transform@after`,
     *            },
     *         })
     *     }
     * }
     * @returns {this} this
     */
    protected useTransform(transforms: Record<string, {
        to: (value: unknown) => any | Promise<any>;
        from: (value: unknown) => any | Promise<any>;
    }>): this;
    /**
     * The "usePrimaryKey" method is add primary keys for database tables.
     *
     * @param {string} primary
     * @returns {this} this
     * @example
     * class User extends Model {
     *     boot() {
     *        this.usePrimaryKey()
     *     }
     * }
     */
    protected usePrimaryKey(primary: string): this;
    /**
     * The "useUUID" method is a concept of using UUIDs (Universally Unique Identifiers) as column 'uuid' in table.
     *
     * It's automatically genarate when created a result.
     * @param {string?} column [column=uuid] make new name column for custom column replace uuid with this
     * @returns {this} this
     * @example
     * class User extends Model {
     *     boot() {
     *        this.useUUID()
     *     }
     * }
     */
    protected useUUID(column?: string): this;
    /**
     * The "useDebug" method is viewer raw-sql logs when excute the results.
     * @returns {this} this
     */
    protected useDebug(): this;
    /**
     * The "usePattern" method is used to assign pattern [snake_case , camelCase].
     * @param  {string} pattern
     * @returns {this} this
     * @example
     * class User extends Model {
     *     boot() {
     *        this.usePattern('camelCase')
     *     }
     * }
     */
    protected usePattern(pattern: TPattern): this;
    /**
     * The "useCamelCase" method is used to assign pattern camelCase.
     * @returns {this} this
     * @example
     * class User extends Model {
     *     boot() {
     *        this.useCamelCase()
     *     }
     * }
     */
    protected useCamelCase(): this;
    /**
     * The "SnakeCase" method is used to assign pattern snake_case.
     * @returns {this} this
     * @example
     * class User extends Model {
     *     boot() {
     *        this.SnakeCase()
     *     }
     * }
     */
    protected useSnakeCase(): this;
    /**
     * The "useSoftDelete" refer to a feature that allows you to "soft delete" records from a database table instead of permanently deleting them.
     *
     * Soft deleting means that the records are not physically removed from the database but are instead marked as deleted by setting a timestamp in a dedicated column.
     *
     * This feature is particularly useful when you want to retain a record of deleted data and potentially recover it later,
     * or when you want to maintain referential integrity in your database
     * @param {string?} column default deleted_at
     * @returns {this} this
     * @example
     * class User extends Model {
     *     boot() {
     *        this.useSoftDelete('deletedAt')
     *     }
     * }
     */
    protected useSoftDelete(column?: string): this;
    /**
     * The "useTimestamp" method is used to assign a timestamp when creating a new record,
     * or updating a record.
     * @param {object} timestampFormat
     * @property {string} timestampFormat.createdAt  - change new name column replace by default [created at]
     * @property {string} timestampFormat.updatedAt - change new name column replace by default updated at
     * @returns {this} this
     * @example
     * class User extends Model {
     *     boot() {
     *        this.useTimestamp({
     *           createdAt : 'createdAt',
     *           updatedAt : 'updatedAt'
     *        })
     *     }
     * }
     */
    protected useTimestamp(timestampFormat?: {
        createdAt: string;
        updatedAt: string;
    }): this;
    /**
     * This "useTable" method is used to assign the name of the table.
     * @param {string} table table name in database
     * @returns {this} this
     * @example
     * class User extends Model {
     *     boot() {
     *        this.useTable('setTableNameIsUser') // => 'setTableNameIsUser'
     *     }
     * }
     */
    protected useTable(table: string): this;
    /**
     * This "useTableSingular" method is used to assign the name of the table with signgular pattern.
     * @returns {this} this
     * @example
     * class User extends Model {
     *     boot() {
     *        this.useTableSingular() // => 'user'
     *     }
     * }
     */
    protected useTableSingular(): this;
    /**
     * This "useTablePlural " method is used to assign the name of the table with pluarl pattern
     * @returns {this} this
     * @example
     * class User extends Model {
     *     boot() {
     *        this.useTablePlural() // => 'users'
     *     }
     * }
     */
    protected useTablePlural(): this;
    /**
     * This 'useValidationSchema' method is used to validate the schema when have some action create or update.
     * @param {Object<ValidateSchema>} schema types (String Number and Date)
     * @returns {this} this
     * @example
     * class User extends Model {
     *   boot() {
     *     this.useValidationSchema({
     *      id : Number,
     *       uuid :  Number,
     *       name : {
     *           type : String,
     *           require : true
     *           // json : true,
     *           // enum : ["1","2","3"]
     *      },
     *      email : {
     *           type : String,
     *           require : true,
     *           length : 199,
     *           match: /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
     *           unique : true,
     *           fn : async (email : string) => /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)
     *       },
     *       createdAt : Date,
     *       updatedAt : Date,
     *       deletedAt : Date
     *    })
     *  }
     * }
     */
    protected useValidationSchema(schema?: TValidateSchema): this;
    /**
     * This 'useValidateSchema' method is used to validate the schema when have some action create or update.
     * @param {Object<ValidateSchema>} schema types (String Number and Date)
     * @returns {this} this
     * @example
     * class User extends Model {
     *   boot() {
     *     this.useValidationSchema({
     *       id : Number,
     *       uuid :  string,
     *       name : {
     *           type : String,
     *           require : true
     *      },
     *      email : {
     *           type : String,
     *           require : true,
     *           length : 199,
     *           // json : true,
     *           // enum : ["1","2","3"]
     *           match: /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
     *           unique : true,
     *           fn : async (email : string) => /^[a-zA-Z0-9._]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(email)
     *       },
     *       createdAt : Date,
     *       updatedAt : Date,
     *       deletedAt : Date
     *    })
     *  }
     * }
     */
    protected useValidateSchema(schema?: TValidateSchema): this;
    /**
     * The "useHooks" method is used to assign hook function when execute returned results to callback function.
     * @param {Function[]} funs functions for callback result
     * @returns {this} this
     * @example
     * class User extends Model {
     *   boot() {
     *     this.useHook([(results) => console.log(results)])
     *   }
     * }
     */
    protected useHooks(funs: Function[]): this;
    /**
     * The "useMiddleware" method is used to register functions that run before the main handler executes.
     *
     * @param {Function} func functions for execute
     * @returns {this} this
     * @example
     * class User extends Model {
     *   boot() {
     *     this.useMiddleware(() => function ...)
     *   }
     * }
     */
    protected useMiddleware(func: Function): this;
    /**
     *
     * The 'useLifecycle' method is used to register lifecycle hooks for model events.
     *
     * Supported lifecycle types:
     * - "beforeInsert"
     * - "afterInsert"
     * - "beforeUpdate"
     * - "afterUpdate"
     * - "beforeRemove"
     * - "afterRemove"
     *
     * Each hook is executed in the order they are registered.
     *
     * @param {LifecycleType} type
     *   The lifecycle event to register. Determines which hook
     *   collection the function(s) will be stored in.
     *
     * @param {Function | Function[]} funcs
     *   A function or array of functions to be executed when the
     *   lifecycle event is triggered. All functions must be valid
     *   JavaScript functions, otherwise an assertion error is thrown.
     *
     * @throws {Error}
     *   Throws if any provided item in `funcs` is not a function.
     *
     * @returns {this}
     *   Returns the current instance to enable method chaining.
     *
     * @example
     * // Register a single hook
     * this.useLifecycle("beforeInsert", () => {
     *   console.log("Before insert hook");
     * });
     *
     * @example
     * // Register multiple hooks
     * this.useLifecycle("afterUpdate", [
     *   () => console.log("Update #1"),
     *   () => console.log("Update #2"),
     * ]);
     *
     * @example
     * // Method chaining
     * this
     *   .useLifecycle("beforeInsert", fnA)
     *   .useLifecycle("afterInsert", fnB);
     */
    protected useLifecycle(type: TLifecycle, funcs: Function | Function[]): this;
    /**
     * The "whenCreatingTable" method is used exection function when creating the table.
     * @param {Function} fn functions for executing when creating the table
     * @returns {this} this
     * @example
     * class User extends Model {
     *   boot() {
     *     this.whenCreatingTable(async () => {
     *         await new User()
     *          .create({
     *            ...columns
     *          })
     *          .save()
     *      })
     *   }
     * }
     */
    protected whenCreatingTable(fn: () => Promise<any> | any): this;
    /**
     * The "onCreatingTable" method is used exection function when creating the table.
     * @param {Function} fn functions for executing when creating the table
     * @returns {this} this
     * @example
     * class User extends Model {
     *   boot() {
     *     this.onCreatingTable(async () => {
     *         await new User()
     *          .create({
     *            ...columns
     *          })
     *          .save()
     *      })
     *   }
     * }
     */
    protected onCreatedTable(fn: () => Promise<any> | any): this;
    /**
     * The "onSyncTable" method is used exection function when sync the table.
     * @param {Function} fn functions for executing when sync table
     * @returns {this} this
     * @example
     * class User extends Model {
     *   boot() {
     *     this.onSyncTable(async () => {
     *        console.log('onSyncTable!!')
     *      })
     *   }
     * }
     */
    onSyncTable(fn: () => Promise<any> | any): this;
    /**
     * exceptColumns for method except
     * @override
     * @returns {promise<string>} string
     */
    protected exceptColumns(): Promise<string[]>;
    /**
     * Build  method for relation in model
     * @param    {string} name name relation registry in your model
     * @param    {Function} callback query callback
     * @returns   {this}   this
     */
    protected buildMethodRelation<K extends T.RelationKeys<this>>(name: K, callback?: Function): this;
    /**
     * The 'audit' method is used to sets the audit information for the tracking.
     *
     * @param {number} userId - The ID of the user performing the audit.
     * @param {Record<string, any>} [metadata] - Optional metadata to store with the audit.
     * @returns {this} this
     */
    audit(userId: number, metadata?: Record<string, any>): this;
    meta(meta: "MAIN" | "SUBORDINATE"): this;
    /**
     * The 'typeOfSchema' method is used get type of schema.
     * @returns {TS} type of schema
     */
    typeOfSchema(): TS;
    /**
     * The 'typeOfRelation' method is used get type of relation.
     * @returns {TR} type of Relation
     */
    typeOfRelation(): TR;
    /**
     * The 'cache' method is used get data from cache.
     * @param {Object}  object
     * @property {string} key key of cache
     * @property {number} expires ms
     * @property {boolean} namespace whether to use namespace for cache key, default is false, namespace is `${database}:${table}:${key}`
     * @returns {this} this
     */
    cache({ key, expires, namespace }: {
        key: string;
        expires: number;
        namespace?: boolean;
    }): this;
    /**
     *
     * @override
     * @param {string[]} ...columns
     * @returns {this} this
     */
    select<K extends T.ColumnKeys<this> | "*">(...columns: K[]): this;
    addSelect<K extends T.ColumnKeys<this>>(...columns: K[]): this;
    /**
     *
     * @override
     * @param {...string} columns
     * @returns {this} this
     */
    except<K extends T.ColumnKeys<this>>(...columns: K[]): this;
    /**
     *
     * @override
     * @returns {this} this
     */
    exceptTimestamp(): this;
    /**
     *
     * @override
     * @param {string} column
     * @param {string?} order by default order = 'asc' but you can used 'asc' or  'desc'
     * @returns {this}
     */
    orderBy<K extends T.ColumnKeys<this>>(column: K, order?: "ASC" | "asc" | "DESC" | "desc"): this;
    /**
     *
     * @override
     * @param {string?} columns [column=id]
     * @returns {this}
     */
    latest<K extends T.ColumnKeys<this>>(...columns: K[]): this;
    /**
     *
     * @override
     * @param {string?} columns [column=id]
     * @returns {this}
     */
    oldest<K extends T.ColumnKeys<this>>(...columns: K[]): this;
    /**
     *
     * @override
     * @param {string?} columns [column=id]
     * @returns {this}
     */
    groupBy<K extends T.ColumnKeys<this>>(...columns: K[]): this;
    /**
     * @override
     * @param {string} column
     * @returns {string} return table.column
     */
    bindColumn(column: string, pattern?: boolean): string;
    /**
     *
     * @override
     * The 'makeSelectStatement' method is used to make select statement.
     * @returns {Promise<string>} string
     */
    makeSelectStatement(): Promise<string>;
    /**
     *
     * @override
     * The 'makeInsertStatement' method is used to make insert table statement.
     * @returns {Promise<string>} string
     */
    makeInsertStatement(): Promise<string>;
    /**
     *
     * @override
     * The 'makeUpdateStatement' method is used to make update table statement.
     * @returns {Promise<string>} string
     */
    makeUpdateStatement(): Promise<string>;
    /**
     *
     * @override
     * The 'makeDeleteStatement' method is used to make delete statement.
     * @returns {Promise<string>} string
     */
    makeDeleteStatement(): Promise<string>;
    /**
     *
     * @override
     * The 'makeCreateTableStatement' method is used to make create table statement.
     * @returns {Promise<string>} string
     */
    makeCreateTableStatement(): Promise<string>;
    /**
     *
     * Clone instance of model
     * @param {Model} instance instance of model
     * @returns {this} this
     */
    clone(instance: Model): this;
    /**
     *
     * Copy an instance of model
     * @param {Model} instance instance of model
     * @param {Object} options keep data
     * @returns {Model} Model
     */
    copyModel(instance: Model, options?: {
        update?: boolean;
        insert?: boolean;
        delete?: boolean;
        where?: boolean;
        limit?: boolean;
        orderBy?: boolean;
        join?: boolean;
        offset?: boolean;
        groupBy?: boolean;
        select?: boolean;
        having?: boolean;
        relations?: boolean;
    }): this;
    /**
     *
     * execute the query using raw sql syntax
     * @override
     * @param {string} sql
     * @returns {this} this
     */
    protected _queryStatement(sql: string, { retry }?: {
        retry?: boolean | undefined;
    }): Promise<any[]>;
    /**
     *
     * execute the query using raw sql syntax actions for insert update and delete
     * @override
     * @param {string} sql
     * @returns {this} this
     */
    protected _actionStatement(sql: string, { retry }?: {
        retry?: boolean | undefined;
    }): Promise<any>;
    /**
     * The 'CTEs' method is used to create common table expressions(CTEs).
     *
     * @override
     * @returns {string} return sql query
     */
    CTEs<M extends Model>(as: string, callback: (query: M) => M, bindModel?: new () => M): this;
    /**
     * The 'disableSoftDelete' method is used to disable the soft delete.
     *
     * @param {boolean} condition
     * @returns {this} this
     */
    disableSoftDelete(condition?: boolean): this;
    /**
     * The 'disableSoftDelete' method is used to disable the soft delete.
     *
     * @param {boolean} condition
     * @returns {this} this
     */
    disableTransform(condition?: boolean): this;
    disabledValidateSchema(condition?: boolean): this;
    /**
     * The 'ignoreSoftDelete' method is used to disable the soft delete.
     * @param {boolean} condition
     * @returns {this} this
     */
    ignoreSoftDelete(condition?: boolean): this;
    /**
     * The 'disableVoid' method is used to disable void.
     *
     * @returns {this} this
     */
    disableVoid(): this;
    /**
     * The 'ignoreVoid' method is used to ignore void.
     *
     * @returns {this} this
     */
    ignoreVoid(): this;
    /**
     * The 'disabledGlobalScope' method is used to disable globalScope.
     *
     * @returns {this} this
     */
    disabledGlobalScope(condition?: boolean): this;
    /**
     * The 'ignoreGlobalScope' method is used to disable globalScope.
     *
     * @returns {this} this
     */
    ignoreGlobalScope(condition?: boolean): this;
    /**
     * The 'with' method is used to eager load related (relations) data when retrieving records from a database.
     *
     * Eager loading allows you to retrieve a primary model and its related models in a more efficient.
     *
     * @param {...string} nameRelations ...name registry in models using (hasOne , hasMany , belongsTo , belongsToMany)
     * @returns {this} this
     * @example
     *   import { Model , TR } from 'tspace-mysql'
     *
     *   class User extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'posts' , model : Post })
     *       }
     *   }
     *
     *   class Post extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'comments' , model : Comment })
     *           this.belongsTo({ name : 'user' , model : User })
     *       }
     *   }
     *  // use 'with' for results of relationship
     *  await new User().with('posts').findMany()
     *
     */
    with<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     * The 'relations' method is used to eager load related (relations) data when retrieving records from a database.
     *
     * Eager loading allows you to retrieve a primary model and its related models in a more efficient.
     *
     * @param {...string} nameRelations ...name registry in models using (hasOne , hasMany , belongsTo , belongsToMany)
     * @returns {this} this
     * @example
     *   import { Model , TR } from 'tspace-mysql'
     *
     *   class User extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'posts' , model : Post })
     *       }
     *   }
     *
     *   class Post extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'comments' , model : Comment })
     *           this.belongsTo({ name : 'user' , model : User })
     *       }
     *   }
     *  // use 'with' for results of relationship
     *  await new User().relations('posts').findMany()
     *
     */
    relations<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     * The 'withAll' method is used to eager load related (relations) data when retrieving records from a database.
     *
     * Eager loading allows you to retrieve a primary model and its related models in a more efficient
     * It's method ignore soft delete
     * @param {...string} nameRelations if data exists return empty
     * @returns {this} this
     */
    withAll<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     * The 'relationsAll' method is used to eager load related (relations) data when retrieving records from a database.
     *
     * Eager loading allows you to retrieve a primary model and its related models in a more efficient.
     *
     * It's method ignore soft delete
     * @param {...string} nameRelations if data exists return empty
     * @returns {this} this
     */
    relationsAll<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     * The 'withCount' method is used to eager load related (relations) data and count data in the relation.
     *
     * @param {...string} nameRelations if data exists return 0
     * @returns {this} this
     */
    withCount<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     * The 'relationsCount' method is used to eager load related (relations) data and count data in the relation.
     *
     * @param {...string} nameRelations if data exists return 0
     * @returns {this} this
     */
    relationsCount<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     * The 'withTrashed' method is used to eager load related (relations) data when retrieving records from a database.
     *
     * Eager loading allows you to retrieve a primary model and its related models in a more efficient.
     *
     * It's method return results only in trash (soft deleted)
     * @param {...string} nameRelations if data exists return blank
     * @returns {this} this
     */
    withTrashed<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     * The 'relationsTrashed' method is used to eager load related (relations) data when retrieving records from a database.
     *
     * Eager loading allows you to retrieve a primary model and its related models in a more efficient.
     *
     * It's method return results only in trash (soft deleted)
     * @param {...string} nameRelations if data exists return blank
     * @returns {this} this
     */
    relationsTrashed<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     * The 'withExists' method is used to eager load related (relations) data when retrieving records from a database.
     *
     * Eager loading allows you to retrieve a primary model and its related models in a more efficient
     * It's method return only exists result of relation query
     * @param {...string} nameRelations
     * @returns {this} this
     * @example
     *   import { Model } from 'tspace-mysql'
     *   class User extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'posts' , model : Post })
     *       }
     *   }
     *
     *   class Post extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'comments' , model : Comment })
     *           this.belongsTo({ name : 'user' , model : User })
     *       }
     *   }
     *  // use with for results of relationship if relations is exists
     *  await new User().withExists('posts').findMany()
     */
    withExists<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     * The 'relationsExists' method is used to eager load related (relations) data when retrieving records from a database.
     *
     * Eager loading allows you to retrieve a primary model and its related models in a more efficient
     * It's method return only exists result of relation query
     * @param {...string} nameRelations
     * @returns {this} this
     * @example
     *   import { Model } from 'tspace-mysql'
     *   class User extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'posts' , model : Post })
     *       }
     *   }
     *
     *   class Post extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'comments' , model : Comment })
     *           this.belongsTo({ name : 'user' , model : User })
     *       }
     *   }
     *  // use with for results of relationship if relations is exists
     *  await new User().relationsExists('posts').findMany()
     */
    relationsExists<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     * The 'has' method is used to eager load related (relations) data when retrieving records from a database.
     *
     * Eager loading allows you to retrieve a primary model and its related models in a more efficient
     * It's method return only exists result of relation query
     * @param {...string} nameRelations
     * @returns {this} this
     * @example
     *   import { Model } from 'tspace-mysql'
     *   import { TRelationOptions } from '../types';
     *   class User extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'posts' , model : Post })
     *       }
     *   }
     *
     *   class Post extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'comments' , model : Comment })
     *           this.belongsTo({ name : 'user' , model : User })
     *       }
     *   }
     *  // use with for results of relationship if relations is exists
     *  await new User().has('posts').findMany()
     */
    has<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     * The 'withNotExists' method is used to eager load related (relations)  data when not exists relation from a database.
     *
     * It's method return only not exists result of relation query
     * @param {...string} nameRelations
     * @returns {this} this
     * @example
  
     *   class User extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'posts' , model : Post })
     *       }
     *   }
     *
     *   class Post extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'comments' , model : Comment })
     *           this.belongsTo({ name : 'user' , model : User })
     *       }
     *   }
     *  // use with for results of relationship if relations is exists
     *  await new User().withNotExists('posts').findMany()
     */
    withNotExists<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     * The 'relationsNotExists' method is used to eager load related (relations)  data when not exists relation from a database.
     *
     * It's method return only not exists result of relation query
     * @param {...string} nameRelations
     * @returns {this} this
     * @example
     *   class User extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'posts' , model : Post })
     *       }
     *   }
     *
     *   class Post extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'comments' , model : Comment })
     *           this.belongsTo({ name : 'user' , model : User })
     *       }
     *   }
     *  // use with for results of relationship if relations is exists
     *  await new User().relationsNotExists('posts').findMany()
     */
    relationsNotExists<K extends T.RelationKeys<this>>(...nameRelations: K[]): this;
    /**
     *
     * The 'withQuery' method is particularly useful when you want to filter or add conditions records based on related data.
     *
     * Use relation '${name}' registry models then return callback queries
     * @param {string} nameRelation name relation in registry in your model
     * @param {function} callback query callback
     * @param {object} options pivot the query
     * @example
     *   import { Model } from 'tspace-mysql'
     *   class User extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'posts' , model : Post })
     *       }
     *   }
     *
     *   class Post extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'comments' , model : Comment })
     *           this.belongsTo({ name : 'user' , model : User })
     *       }
     *   }
     *
     *   class Comment extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'users' , model : User })
     *           this.belongsTo({ name : 'post' , model : Post })
     *       }
     *   }
     *
     *   await new User().relations('posts')
     *   .withQuery('posts', (query : Post) => {
     *       return query.relations('comments','user')
     *       .withQuery('comments', (query : Comment) => {
     *           return query.relations('user','post')
     *       })
     *       .withQuery('user', (query : User) => {
     *           return query.relations('posts').withQuery('posts',(query : Post)=> {
     *               return query.relations('comments','user')
     *               // relation n, n, ...n
     *           })
     *       })
     *   })
     *  .findMany()
     * @returns {this} this
     */
    withQuery<K extends T.RelationKeys<this>, R extends T.Relations<this>>(nameRelation: K, callback: (query: `$${K & string}` extends keyof R ? R[`$${K & string}`] extends (infer X)[] ? X : R[`$${K & string}`] extends Model ? R[`$${K & string}`] : Model : K extends keyof R ? R[K] extends (infer X)[] ? X : R[K] extends Model ? R[K] : Model : Model) => any, options?: {
        pivot: boolean;
    }): this;
    withQueryExists<K extends T.RelationKeys<this>, R extends T.Relations<this>>(nameRelation: K, callback: (query: `$${K & string}` extends keyof R ? R[`$${K & string}`] extends (infer X)[] ? X : R[`$${K & string}`] extends Model ? R[`$${K & string}`] : Model : K extends keyof R ? R[K] extends (infer X)[] ? X : R[K] extends Model ? R[K] : Model : Model) => any, options?: {
        pivot: boolean;
    }): this;
    /**
     *
     * The 'relationQuery' method is particularly useful when you want to filter or add conditions records based on related data.
     *
     * Use relation '${name}' registry models then return callback queries
     * @param {string} nameRelation name relation in registry in your model
     * @param {function} callback query callback
     * @param {object} options pivot the query
     * @example
     *   import { Model } from 'tspace-mysql'
     *   class User extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'posts' , model : Post })
     *       }
     *   }
     *
     *   class Post extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'comments' , model : Comment })
     *           this.belongsTo({ name : 'user' , model : User })
     *       }
     *   }
     *
     *   class Comment extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'users' , model : User })
     *           this.belongsTo({ name : 'post' , model : Post })
     *       }
     *   }
     *
     *   await new User().relations('posts')
     *   .relationQuery('posts', (query : Post) => {
     *       return query.relations('comments','user')
     *       .relationQuery('comments', (query : Comment) => {
     *           return query.relations('user','post')
     *       })
     *       .relationQuery('user', (query : User) => {
     *           return query.relations('posts').relationsQuery('posts',(query : Post)=> {
     *               return query.relations('comments','user')
     *               // relation n, n, ...n
     *           })
     *       })
     *   })
     *  .findMany()
     * @returns {this} this
     */
    relationQuery<K extends T.RelationKeys<this>, R extends T.Relations<this>>(nameRelation: K, callback: (query: `$${K & string}` extends keyof R ? R[`$${K & string}`] extends (infer X)[] ? X : R[`$${K & string}`] extends Model ? R[`$${K & string}`] : Model : K extends keyof R ? R[K] extends (infer X)[] ? X : R[K] extends Model ? R[K] : Model : Model) => any, options?: {
        pivot: boolean;
    }): this;
    /**
     *
     * The 'relationQueryExists' method is particularly useful when you want to filter or add conditions records based on related data.
     *
     * Use relation '${name}' registry models then return callback queries
     * @param {string} nameRelation name relation in registry in your model
     * @param {function} callback query callback
     * @param {object} options pivot the query
     * @example
     *   import { Model } from 'tspace-mysql'
     *   class User extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'posts' , model : Post })
     *       }
     *   }
     *
     *   class Post extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'comments' , model : Comment })
     *           this.belongsTo({ name : 'user' , model : User })
     *       }
     *   }
     *
     *   class Comment extends Model {
     *       constructor(){
     *           super()
     *           this.hasMany({ name : 'users' , model : User })
     *           this.belongsTo({ name : 'post' , model : Post })
     *       }
     *   }
     *
     *   await new User().relations('posts')
     *   .relationQuery('posts', (query : Post) => {
     *       return query.relations('comments','user')
     *       .relationQuery('comments', (query : Comment) => {
     *           return query.relations('user','post')
     *       })
     *       .relationQuery('user', (query : User) => {
     *           return query.relations('posts').relationsQuery('posts',(query : Post)=> {
     *               return query.relations('comments','user')
     *               // relation n, n, ...n
     *           })
     *       })
     *   })
     *  .findMany()
     * @returns {this} this
     */
    relationQueryExists<K extends T.RelationKeys<this>, R extends T.Relations<this>>(nameRelation: K, callback: (query: `$${K & string}` extends keyof R ? R[`$${K & string}`] extends (infer X)[] ? X : R[`$${K & string}`] extends Model ? R[`$${K & string}`] : Model : K extends keyof R ? R[K] extends (infer X)[] ? X : R[K] extends Model ? R[K] : Model : Model) => any, options?: {
        pivot: boolean;
    }): this;
    /**
     *
     * The 'findWithQuery' method is used to find instance call back from relation.
     *
     * @param {string} name name relation in registry in your model
     * @returns {Model} model instance
     */
    findWithQuery<K extends T.RelationKeys<this>>(name: K): Model | null;
    /**
     * The 'hasOne' relationship defines a one-to-one relationship between two database tables.
     *
     * It indicates that a particular record in the primary table is associated with one and only one record in the related table.
     *
     * This is typically used when you have a foreign key in the related table that references the primary table.
     *
     * @param    {object} relations registry relation in your model
     * @property {string} relation.name
     * @property {string} relation.as
     * @property {class}  relation.model
     * @property {string} relation.localKey
     * @property {string} relation.foreignKey
     * @property {string} relation.freezeTable
     * @returns  {this}   this
     */
    protected hasOne<K extends TR extends object ? TRelationKeys<TR> : string>({ name, as, model, localKey, foreignKey, freezeTable, }: TRelationOptions<K>): this;
    /**
     * The 'hasMany' relationship defines a one-to-many relationship between two database tables.
     *
     * It indicates that a record in the primary table can be associated with multiple records in the related table.
     *
     * This is typically used when you have a foreign key in the related table that references the primary table.
     *
     * @param    {object} relations registry relation in your model
     * @property {string} relation.name
     * @property {string} relation.as
     * @property {class}  relation.model
     * @property {string} relation.localKey
     * @property {string} relation.foreignKey
     * @property {string} relation.freezeTable
     * @returns   {this}   this
     */
    protected hasMany<K extends TR extends object ? TRelationKeys<TR> : string>({ name, as, model, localKey, foreignKey, freezeTable, }: TRelationOptions<K>): this;
    /**
     * The 'belongsTo' relationship defines a one-to-one or many-to-one relationship between two database tables.
     *
     * It indicates that a record in the related table belongs to a single record in the primary table.
     *
     * This is typically used when you have a foreign key in the primary table that references the related table.
     *
     * @param    {object} relations registry relation in your model
     * @property {string} relation.name
     * @property {string} relation.as
     * @property {class}  relation.model
     * @property {string} relation.localKey
     * @property {string} relation.foreignKey
     * @property {string} relation.freezeTable
     * @returns   {this}   this
     */
    protected belongsTo<K extends TR extends object ? TRelationKeys<TR> : string>({ name, as, model, localKey, foreignKey, freezeTable, }: TRelationOptions<K>): this;
    /**
     * The 'belongsToMany' relationship defines a many-to-many relationship between two database tables.
     *
     * It indicates that records in both the primary table and the related table can be associated
     * with multiple records in each other's table through an intermediate table.
     *
     * This is commonly used when you have a many-to-many relationship between entities, such as users and roles or products and categories.
     * @param    {object} relations registry relation in your model
     * @property {string} relation.name
     * @property {string} relation.as
     * @property {class}  relation.model
     * @property {string} relation.localKey
     * @property {string} relation.foreignKey
     * @property {string} relation.freezeTable freeae table name
     * @property {string} relation.pivot table name of pivot
     * @property {string} relation.oldVersion return value of old version
     * @property {class?} relation.modelPivot model for pivot
     * @returns  {this}   this
     */
    protected belongsToMany<K extends TR extends object ? TRelationKeys<TR> : string>({ name, as, model, localKey, foreignKey, freezeTable, pivot, oldVersion, modelPivot, }: TRelationOptions<K>): this;
    /**
     * The 'belongsToManySingle' relationship defines a many-to-many relationship between two database tables.
     * But return object
     *
     * It indicates that records in both the primary table and the related table can be associated
     * with multiple records in each other's table through an intermediate table.
     *
     * This is commonly used when you have a many-to-many relationship between entities, such as users and roles or products and categories.
     * @param    {object} relations registry relation in your model
     * @property {string} relation.name
     * @property {string} relation.as
     * @property {class}  relation.model
     * @property {string} relation.localKey
     * @property {string} relation.foreignKey
     * @property {string} relation.freezeTable freeae table name
     * @property {string} relation.pivot table name of pivot
     * @property {string} relation.oldVersion return value of old version
     * @property {class?} relation.modelPivot model for pivot
     * @returns  {this}   this
     */
    protected belongsToManySingle<K extends TR extends object ? TRelationKeys<TR> : string>({ name, as, model, localKey, foreignKey, freezeTable, pivot, oldVersion, modelPivot, }: TRelationOptions<K>): this;
    /**
     * The 'hasOneBuilder' method is useful for creating 'hasOne' relationship to function
     *
     * @param    {object}  relation registry relation in your model
     * @type     {object}  relation
     * @property {class}   model
     * @property {string?} name
     * @property {string?} as
     * @property {string?} localKey
     * @property {string?} foreignKey
     * @property {string?} freezeTable
     * @param    {Function?} callback callback of query
     * @returns  {this} this
     */
    protected hasOneBuilder({ name, as, model, localKey, foreignKey, freezeTable, }: TRelationQueryOptions, callback?: Function): this;
    /**
     * The 'hasManyBuilder' method is useful for creating 'hasMany' relationship to function
     *
     * @param    {object}  relation registry relation in your model
     * @type     {object}  relation
     * @property {class}   model
     * @property {string?} name
     * @property {string?} as
     * @property {string?} localKey
     * @property {string?} foreignKey
     * @property {string?} freezeTable
     * @param    {function?} callback callback of query
     * @returns  {this} this
     */
    protected hasManyBuilder({ name, as, model, localKey, foreignKey, freezeTable, }: TRelationQueryOptions, callback?: Function): this;
    /**
     * The 'belongsToBuilder' method is useful for creating 'belongsTo' relationship to function
     * @param    {object}  relation registry relation in your model
     * @type     {object}  relation
     * @property {class}   model
     * @property {string?} name
     * @property {string?} as
     * @property {string?} localKey
     * @property {string?} foreignKey
     * @property {string?} freezeTable
     * @param    {function?} callback callback of query
     * @returns  {this} this
     */
    protected belongsToBuilder({ name, as, model, localKey, foreignKey, freezeTable, }: TRelationQueryOptions, callback?: Function): this;
    /**
     * The 'belongsToManyBuilder' method is useful for creating 'belongsToMany' relationship to function
     *
     * @param    {object}  relation registry relation in your model
     * @type     {object}  relation
     * @property {class}   model
     * @property {string?} name
     * @property {string?} as
     * @property {string?} localKey
     * @property {string?} foreignKey
     * @property {string?} freezeTable
     * @param    {function?} callback callback of query
     * @returns  {this} this
     */
    protected belongsToManyBuilder({ name, as, model, localKey, foreignKey, freezeTable, pivot, oldVersion, modelPivot, }: TRelationQueryOptions, callback?: Function): this;
    /**
     * The 'trashed' method is used to specify that you want to retrieve only the soft-deleted records from a database table.
     *
     * Soft deleting is a feature that allows you to mark records as deleted without physically removing them from the database. Instead,
     * a special "deleted_at" timestamp column is set to a non-null value to indicate that the record has been deleted.
     * @returns {this} this
     */
    onlyTrashed(): this;
    /**
     * The 'trashed' method is used to specify that you want to retrieve only the soft-deleted records from a database table.
     *
     * Soft deleting is a feature that allows you to mark records as deleted without physically removing them from the database. Instead,
     * a special "deleted_at" timestamp column is set to a non-null value to indicate that the record has been deleted.
     * @returns {this} this
     */
    trashed(): this;
    /**
     * restore data in trashed
     * @returns {promise}
     */
    restore(): Promise<T.Result<this>[]>;
    /**
     *
     * @returns {string} string
     */
    toTableName(): string | null;
    /**
     *
     * @param {string} column
     * @returns {string} string
     */
    toTableNameAndColumn(column: string): string;
    where<K extends T.ColumnKeys<this>, V extends (K & keyof T.ColumnOptions<this> extends never ? any : T.ColumnOptions<this>[K & keyof T.ColumnOptions<this>])>(column: K, value: V): this;
    where<K extends T.ColumnKeys<this>, V extends (K & keyof T.ColumnOptions<this> extends never ? any : T.ColumnOptions<this>[K & keyof T.ColumnOptions<this>])>(column: K, operator: "=" | "<" | ">" | "!=" | "<>" | "<=" | ">=" | "LIKE" | "like", value: V): this;
    where(column: Partial<{
        [K in keyof T.ColumnOptions<this>]: T.ColumnOptions<this>[K];
    }>): this;
    /**
    * @override
    * @param {string | K} column if arguments is object
    * @param {any?} value
    * @returns {this} this
    */
    orWhere<K extends T.ColumnKeys<this>, V extends (K & keyof T.ColumnOptions<this> extends never ? any : T.ColumnOptions<this>[K & keyof T.ColumnOptions<this>])>(column: K, value: V): this;
    /**
     * @override
     * @param {string | K} column if arguments is object
     * @param {string?} operator "=" | "<" | ">" | "!=" | "<>" | "<=" | ">=" | "LIKE"  | "like"
     * @param {any?} value
     * @returns {this} this
     */
    orWhere<K extends T.ColumnKeys<this>, V extends (K & keyof T.ColumnOptions<this> extends never ? any : T.ColumnOptions<this>[K & keyof T.ColumnOptions<this>])>(column: K, operator: "=" | "<" | ">" | "!=" | "<>" | "<=" | ">=" | "LIKE" | "like", value: V): this;
    /**
     * @override
     * @param {string} column
     * @param {number} day
     * @returns {this}
     */
    whereDay<K extends T.ColumnKeys<this>>(column: K, day: number): this;
    /**
     * @override
     * @param {string} column
     * @param {number} month
     * @returns {this}
     */
    whereMonth<K extends T.ColumnKeys<this>>(column: K, month: number): this;
    /**
     * @override
     * @param {string} column
     * @param {number} year
     * @returns {this}
     */
    whereYear<K extends T.ColumnKeys<this>>(column: K, year: number): this;
    /**
     * @override
     * @param {Object} columns
     * @returns {this}
     */
    whereObject<K extends T.ColumnKeys<this>, T extends T.ColumnOptions<this>>(columns: {
        [P in K & keyof T]: T[P];
    }): this;
    /**
     * @override
     * @param    {string} column
     * @param    {object}  property object { key , value , operator }
     * @property {string}  property.key
     * @property {string}  property.value
     * @property {string?} property.operator
     * @returns   {this}
     */
    whereJSON<K extends T.ColumnKeys<this>>(column: K, { key, value, operator }: {
        key: string;
        value: string;
        operator?: string;
    }): this;
    /**
     * @override
     * @param    {string} column
     * @param    {object}  property object { key , value , operator }
     * @property {string}  property.key
     * @property {string}  property.value
     * @property {string?} property.operator
     * @returns   {this}
     */
    whereJson<K extends T.ColumnKeys<this>>(column: K, { key, value, operator }: {
        key: string;
        value: string;
        operator?: string;
    }): this;
    /**
     * @override
     * @param {number} userId
     * @param {string?} column custom it *if column is not user_id
     * @returns {this}
     */
    whereUser(userId: number, column?: string): this;
    /**
     * @override
     * @param {string} sql
     * @returns {this}
     */
    whereExists(sql: string | Model | DB): this;
    /**
     * @override
     * @param {string} column
     * @param {array} array
     * @returns {this}
     */
    whereIn<K extends T.ColumnKeys<this>>(column: K, array: any[]): this;
    /**
     * @override
     * @param {string} column
     * @param {array} array
     * @returns {this}
     */
    orWhereIn<K extends T.ColumnKeys<this>>(column: K, array: any[]): this;
    /**
     * @override
     * @param {string} column
     * @param {array} array
     * @returns {this}
     */
    whereNotIn<K extends T.ColumnKeys<this>>(column: K, array: any[]): this;
    /**
     * @override
     * @param {string} column
     * @param {array} array
     * @returns {this}
     */
    orWhereNotIn<K extends T.ColumnKeys<this>>(column: K, array: any[]): this;
    /**
     * @override
     * @param {string} column
     * @param {string} subQuery
     * @returns {this}
     */
    whereSubQuery<K extends T.ColumnKeys<this>>(column: K, subQuery: string | Model | DB, options?: {
        operator?: (typeof CONSTANTS)["EQ"] | (typeof CONSTANTS)["IN"];
    }): this;
    /**
     * @override
     * @param {string} column
     * @param {string} subQuery
     * @returns {this}
     */
    whereNotSubQuery<K extends T.ColumnKeys<this>>(column: K, subQuery: string | Model | DB, options?: {
        operator?: (typeof CONSTANTS)["NOT_EQ"] | (typeof CONSTANTS)["NOT_IN"];
    }): this;
    /**
     * @override
     * @param {string} column
     * @param {string} subQuery
     * @returns {this}
     */
    orWhereSubQuery<K extends T.ColumnKeys<this>>(column: K, subQuery: string | Model | DB, options?: {
        operator?: (typeof CONSTANTS)["EQ"] | (typeof CONSTANTS)["IN"];
    }): this;
    /**
     * @override
     * @param {string} column
     * @param {string} subQuery
     * @returns {this}
     */
    orWhereNotSubQuery<K extends T.ColumnKeys<this>>(column: K, subQuery: string | Model | DB, options?: {
        operator?: (typeof CONSTANTS)["NOT_EQ"] | (typeof CONSTANTS)["NOT_IN"];
    }): this;
    /**
     * @override
     * @param {string} column
     * @param {array} array
     * @returns {this}
     */
    whereBetween<K extends T.ColumnKeys<this>, V extends (K & keyof T.ColumnOptions<this> extends never ? any : T.ColumnOptions<this>[K & keyof T.ColumnOptions<this>])>(column: K, array: [V, V]): this;
    /**
     * @override
     * @param {string} column
     * @param {array} array
     * @returns {this}
     */
    orWhereBetween<K extends T.ColumnKeys<this>, V extends (K & keyof T.ColumnOptions<this> extends never ? any : T.ColumnOptions<this>[K & keyof T.ColumnOptions<this>])>(column: K, array: [V, V]): this;
    /**
     * @override
     * @param {string} column
     * @param {array} array
     * @returns {this}
     */
    whereNotBetween<K extends T.ColumnKeys<this>, V extends (K & keyof T.ColumnOptions<this> extends never ? any : T.ColumnOptions<this>[K & keyof T.ColumnOptions<this>])>(column: K, array: [V, V]): this;
    /**
     * @override
     * @param {string} column
     * @param {array} array
     * @returns {this}
     */
    orWhereNotBetween<K extends T.ColumnKeys<this>, V extends (K & keyof T.ColumnOptions<this> extends never ? any : T.ColumnOptions<this>[K & keyof T.ColumnOptions<this>])>(column: K, array: [V, V]): this;
    /**
     * @override
     * @param {string} column
     * @returns {this}
     */
    whereNull<K extends T.ColumnKeys<this>>(column: K): this;
    /**
     * @override
     * @param {string} column
     * @returns {this}
     */
    orWhereNull<K extends T.ColumnKeys<this>>(column: K): this;
    /**
     * @override
     * @param {string} column
     * @returns {this}
     */
    whereNotNull<K extends T.ColumnKeys<this>>(column: K): this;
    /**
     * @override
     * @param {string} column
     * @returns {this}
     */
    orWhereNotNull<K extends T.ColumnKeys<this>>(column: K): this;
    /**
     * @override
     * @param {string} column
     * @param {string?} operator = < > != !< !>
     * @param {any?} value
     * @returns {this}
     */
    whereSensitive<K extends T.ColumnKeys<this>>(column: K, operator?: any, value?: any): this;
    /**
     * @override
     * @param {string} column
     * @param {string?} operator = < > != !< !>
     * @param {any?} value
     * @returns {this}
     */
    whereStrict<K extends T.ColumnKeys<this>>(column: K, operator?: any, value?: any): this;
    /**
     * @override
     * @param {string} column
     * @param {string?} operator = < > != !< !>
     * @param {any?} value
     * @returns {this}
     */
    orWhereSensitive<K extends T.ColumnKeys<this>>(column: K, operator?: any, value?: any): this;
    /**
     * The 'whereHas' method is used to checks if a relationship exists.
     * Only get the parent models where the related model(s) match a given condition.
     *
     * @param {string} nameRelation
     * @param {model} callback callback query
     * @returns {this}
     */
    whereHas<K extends T.RelationKeys<this>, R extends T.Relations<this>>(nameRelation: K, callback: (query: `$${K & string}` extends keyof R ? R[`$${K & string}`] extends (infer X)[] ? X : R[`$${K & string}`] extends Model ? R[`$${K & string}`] : Model : K extends keyof R ? R[K] extends (infer X)[] ? X : R[K] extends Model ? R[K] : Model : Model) => any): this;
    /**
     * The 'whereNotHas' method is used to checks if a relationship not exists.
     *
     * @param {string} nameRelation
     * @param {model} callback callback query
     * @returns {this}
     */
    whereNotHas<K extends T.RelationKeys<this>, R extends T.Relations<this>>(nameRelation: K, callback: (query: `$${K & string}` extends keyof R ? R[`$${K & string}`] extends (infer X)[] ? X : R[`$${K & string}`] extends Model ? R[`$${K & string}`] : Model : K extends keyof R ? R[K] extends (infer X)[] ? X : R[K] extends Model ? R[K] : Model : Model) => any): this;
    /**
     * @override
     * @param {Function} callback callback query
     * @returns {this}
     */
    whereQuery<T extends Model | unknown, M = T extends this ? this : T extends Model ? T : this>(callback: (query: M) => M): this;
    /**
     * @override
     * @param {Function} callback callback query
     * @returns {this}
     */
    orWhereQuery<T extends Model | unknown, M = T extends this ? this : T extends Model ? T : this>(callback: (query: M) => M): this;
    /**
     * @override
     * @param {string[]} columns
     * @param {string?} operator ['=', '<', '>' ,'!=', '!<', '!>' ,'LIKE']
     * @param {any?} value
     * @returns {this}
     */
    whereAny<K extends T.ColumnKeys<this>>(columns: K[], operator?: any, value?: any): this;
    /**
     * The 'whereAll' method is used to clause to a database query.
     *
     * This method allows you to specify conditions that the retrieved records must meet.
     *
     * If has only 2 arguments default operator '='
     * @param {string[]} columns
     * @param {string?} operator ['=', '<', '>' ,'!=', '!<', '!>' ,'LIKE']
     * @param {any?} value
     * @returns {this}
     */
    whereAll<K extends T.ColumnKeys<this>>(columns: K[], operator?: any, value?: any): this;
    /**
     * The 'when' method is used to specify if condition should be true will be next to the actions
     *
     * @override
     * @param {string | number | undefined | null | Boolean} condition when condition true will return query callback
     * @returns {this} this
     */
    when<T extends Model | unknown, M = T extends this ? this : T extends Model ? T : this>(condition: string | number | undefined | null | boolean, callback: (query: M) => M): this;
    /**
     * This 'union' method is used to union statement sql
     *
     * @override
     * @param {string} sql
     * @returns {this} this
     */
    union(sql: string | Model): this;
    /**
     * This 'union' method is used to union statement sql
     *
     * @override
     * @param {string} sql
     * @returns {this} this
     */
    unionAll(sql: string | Model): this;
    /**
     * @override
     * @param {string | TModelOrObject | Join} localKey local key in current table or using Model
     * @param {string | TModelOrObject | Join} referenceKey reference key in next table or using Model
     * @example
     * await new User()
     * .select('users.id as userId','posts.id as postId','email')
     * .join('users.id','posts.id')
     * .join('posts.category_id','categories.id')
     * .where('users.id',1)
     * .where('posts.id',2)
     * .get()
     *
     *  await new User()
     * .select('users.id as userId','posts.id as postId','email')
     * .join(User,Post)
     * .join(Post,Category)
     * .get()
     *
     *
     * @returns {this}
     */
    join(localKey: `${string}.${string}` | ((join: Join) => Join) | TModelOrObject, referenceKey?: `${string}.${string}` | TModelOrObject): this;
    /**
     *
     * @override
     * @param {string} localKey local key in current table
     * @param {string} referenceKey reference key in next table
     * @returns {this}
     */
    rightJoin(localKey: `${string}.${string}` | ((join: Join) => Join) | TModelOrObject, referenceKey?: `${string}.${string}` | TModelOrObject): this;
    /**
     *
     * @override
     * @param {string} localKey local key in current table
     * @param {string} referenceKey reference key in next table
     * @returns {this}
     */
    leftJoin(localKey: `${string}.${string}` | ((join: Join) => Join) | TModelOrObject, referenceKey?: `${string}.${string}` | TModelOrObject): this;
    /**
     * @override
     * @param {string} localKey local key in current table
     * @param {string} referenceKey reference key in next table
     * @returns {this}
     */
    crossJoin(localKey: `${string}.${string}` | ((join: Join) => Join) | TModelOrObject, referenceKey?: `${string}.${string}` | TModelOrObject): this;
    /**
     * @override
     * @param    {object}  property object { localKey , foreignKey , sqlr }
     * @property {string} property.localKey local key in current table
     * @property {string} property.foreignKey reference key in next table
     * @property {string} property.sql sql string
     * @example
     * await new DB('users')
     * .joinSubQuery({ localKey : 'id' , foreignKey : 'userId' , sql : '....sql'})
     * .get()
     * @returns {this}
     */
    joinSubQuery({ localKey, foreignKey, sql, }: {
        localKey: string;
        foreignKey: string;
        sql: string | Model | DB;
    }): this;
    /**
     * The 'joinModel' method is used to perform a join operation between two Models.
     *
     * Joins are used to combine data from different tables based on a specified condition, allowing you to retrieve data from related tables in a single query.
     *
     * @param   {TModelOrObject} m1  main Model
     * @param   {TModelOrObject} m2 reference Model
     * @returns {this}
     */
    joinModel(m1: TModelOrObject | ((join: JoinModel) => JoinModel), m2?: TModelOrObject): this;
    /**
     * The 'rightJoinModel' method is used to perform a join operation between two Models.
     *
     * A right join, also known as a right outer join, retrieves all rows from the right table and the matching rows from the left table.
     *
     * If there is no match in the left table, NULL values are returned for columns from the left table
     * @param   {TModelOrObject} m1  main Model
     * @param   {TModelOrObject} m2  reference Model
     * @returns {this}
     */
    rightJoinModel(m1: TModelOrObject | ((join: JoinModel) => JoinModel), m2?: TModelOrObject): this;
    /**
     * The 'leftJoinModel' method is used to perform a left join operation between two database tables.
     *
     * A left join retrieves all rows from the left table and the matching rows from the right table.
     *
     * If there is no match in the right table, NULL values are returned for columns from the right table.
     * @param   {TModelOrObject} m1  main Model
     * @param   {TModelOrObject} m2  reference Model
     * @returns {this}
     */
    leftJoinModel(m1: TModelOrObject | ((join: JoinModel) => JoinModel), m2?: TModelOrObject): this;
    /**
     * The 'crossJoinModel' method performs a cross join operation between two or more tables.
     *
     * A cross join, also known as a Cartesian join, combines every row from the first table with every row from the second table.
     *
     * @param   {TModelOrObject} m1  main Model
     * @param   {TModelOrObject} m2  reference Model
     * @returns {this}
     */
    crossJoinModel(m1: TModelOrObject | ((join: JoinModel) => JoinModel), m2?: TModelOrObject): this;
    /**
     *
     * @override
     * @param {string=} column [column=id]
     * @returns {promise<number>}
     */
    count<K extends T.ColumnKeys<this> | "id" | "_id">(c?: K): Promise<number>;
    /**
     *
     * @override
     * @param {string=} column [column=id]
     * @returns {promise<number>}
     */
    avg<K extends T.ColumnKeys<this> | "id" | "_id">(c?: K): Promise<number>;
    /**
     *
     * @override
     * @param {string=} column [column=id]
     * @returns {promise<number>}
     */
    sum<K extends T.ColumnKeys<this> | "id" | "_id">(c?: K): Promise<number>;
    /**
     *
     * @override
     * @param {string=} column [column=id]
     * @returns {promise<number>}
     */
    max<K extends T.ColumnKeys<this> | "id" | "_id">(c?: K): Promise<number>;
    /**
     * @override
     * @param {string} c
     * @returns {promise<number>}
     */
    min<K extends T.ColumnKeys<this> | "id" | "_id">(c: K): Promise<number>;
    /**
     * @override
     * @returns {promise<boolean>} promise boolean
     */
    delete(): Promise<T.DeleteResult>;
    /**
     * @override
     * @returns {promise<boolean>} promise boolean
     */
    deleteMany(): Promise<boolean>;
    /**
     *
     * The 'forceDelete' method is used to delete records from a database table based on the specified query conditions.
     *
     * It allows you to remove one or more records that match certain criteria.
     *
     * This method should be ignore the soft delete
     * @returns {promise<boolean>}
     */
    forceDelete(): Promise<boolean>;
    /**
     *
     * @override
     * @param {object} options
     * @property {boolean} options.latest
     * @property {boolean} options.oldest
     * @returns {string} return sql query
     */
    toString({ latest, oldest, }?: {
        latest?: boolean;
        oldest?: boolean;
    }): string;
    /**
     *
     * @override
     * @param {object} options
     * @property {boolean} options.latest
     * @property {boolean} options.oldest
     * @returns {string} return sql query
     */
    toSQL({ latest, oldest, }?: {
        latest?: boolean;
        oldest?: boolean;
    }): string;
    /**
     * @override
     * @param {string=} column [column=id]
     * @returns {promise<Array>}
     */
    toArray<K extends T.ColumnKeys<this> | "id">(column?: K): Promise<any[]>;
    /**
     *
     * @override
     * @returns {promise<boolean>}
     */
    exists(): Promise<boolean>;
    /**
     *
     * @override
     * @param {Function?} cb callback function return query sql
     * @returns {promise<Record<string,any> | null>} Record | null
     */
    first<K>(cb?: Function): Promise<T.Result<this, K> | null>;
    /**
     * @override
     * @param {Function?} cb callback function return query sql
     * @returns {promise<Record<string,any> | null>} Record | null
     */
    findOne<K>(cb?: Function): Promise<T.Result<this, K> | null>;
    /**
     * @override
     * @param {number} id callback function return query sql
     * @returns {promise<Record<string,any> | null>} Record | null
     */
    find<K>(primaryKey: number | string): Promise<T.Result<this, K> | null>;
    /**
     * @override
     * @returns {promise<object | Error>} Record | throw error
     */
    firstOrError<K>(message?: string, options?: Record<string, any>): Promise<T.Result<this, K>>;
    /**
     *
     * @override
     * @returns {promise<T.Result<this>>} Record | throw error
     */
    findOneOrError<K>(message?: string, options?: Record<string, any>): Promise<T.Result<this, K>>;
    /**
     *
     * @override
     * @param {Function?} cb callback function return query sql
     * @returns {promise<array>} Array
     */
    get<K>(cb?: Function): Promise<T.Result<this, K>[]>;
    /**
     *
     * @override
     * @param {Function?} cb callback function return query sql
     * @returns {promise<array>} Array
     */
    findMany<K>(cb?: Function): Promise<T.Result<this, K>[]>;
    /**
     * @override
     * @param    {object?} paginationOptions by default page = 1 , limit = 15
     * @property {number} paginationOptions.limit
     * @property {number} paginationOptions.page
     * @returns  {promise<Pagination>} Pagination
     */
    pagination<K>(paginationOptions?: {
        limit?: number;
        page?: number;
        alias?: boolean;
    }): Promise<T.PaginateResult<this, K>>;
    /**
     *
     * @override
     * @param     {?object} paginationOptions by default page = 1 , limit = 15
     * @property  {number}  paginationOptions.limit
     * @property  {number}  paginationOptions.page
     * @returns   {promise<Pagination>} Pagination
     */
    paginate<K>(paginationOptions?: {
        limit?: number;
        page?: number;
        alias?: boolean;
    }): Promise<T.PaginateResult<this, K>>;
    /**
     * @override
     * @param {string} column
     * @example
     *  const results = await new Post()
     * .getGroupBy('user_id')
     *
     *  // you can find with user id in the results
     *  const postsByUserId1 = results.get(1)
     * @returns {Promise<object>} Object binding with your column pairs
     */
    getGroupBy<K, C extends T.ColumnKeys<this>>(column: C): Promise<Map<string | number, T.Result<this, K>[]>>;
    /**
     * @override
     * @param {string} column
     * @example
     *  const results = await new Post()
     * .getGroupBy('user_id')
     *
     *  // you can find with user id in the results
     *  const postsByUserId1 = results.get(1)
     * @returns {Promise<object>} Object binding with your column pairs
     */
    findGroupBy<K, C extends T.ColumnKeys<this>>(column: C): Promise<Map<string | number, T.Result<this, K>[]>>;
    /**
     * @override
     * @param {object} data for insert
     * @returns {this} this
     */
    insert<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: {
        [P in Exclude<K & keyof C, "id" | "_id" | "uuid"> as null extends C[P] ? any : P]: Extract<C[P], Date> extends never ? Extract<C[P], Record<string, unknown>> extends never ? C[P] : string : any;
    }): this;
    /**
     * @override
     * @param {object} data for insert
     * @returns {this} this
     */
    create<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>): this;
    /**
     * @override
     * @param {object} data
     * @param {array?} updateNotExists options for except update some records in your ${data}
     * @returns {this} this
     */
    update<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.UpdateInput<K, C>, updateNotExists?: T.ColumnKeys<this>[]): this;
    /**
     * @override
     * @param {object} data
     * @param {array?} updateNotExists options for except update some records in your ${data}
     * @returns {this} this
     */
    updateMany<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.UpdateInput<K, C>, updateNotExists?: string[]): this;
    /**
     *
     * @override
     * @param {Array<{when: Record<string, string | number | boolean | null | undefined>, columns: Record<string, string | number | boolean | null | undefined>}>>} cases
     *   An array of update cases.
     *   - `when` is an object specifying the conditions to match records.
     *   - `columns` is an object specifying the new values to set for the matched records.
     *
     * @property {Record<string,string | number | boolean | null | undefined>}  cases.when
     * @property {Record<string,string | number | boolean | null | undefined>}  cases.columns
     * @returns {this} this
     */
    updateCases<T extends T.ColumnOptions<this>, K extends keyof T, U extends Model | unknown, M = U extends this ? this : U extends Model ? U : this>(cases: {
        condition: ((query: M) => M) | Partial<{
            [P in K & keyof T]: Extract<T[P], Record<string, unknown>> extends never ? T[P] : string;
        }>;
        columns: Partial<{
            [P in K & keyof T]: Extract<T[P], Record<string, unknown>> extends never ? T[P] : string;
        }>;
    }[]): this;
    /**
     * @override
     * @param {object} data
     * @returns {this} this
     */
    updateNotExists<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.UpdateInput<K, C>): this;
    /**
     * @override
     * @param {object} data for update or create
     * @returns {this} this
     */
    updateOrCreate<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>): this;
    /**
     * @override
     * @param {object} data for update or create
     * @returns {this} this
     */
    updateOrInsert<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>): this;
    /**
     * @override
     * @param {object} data for update or create
     * @returns {this} this
     */
    insertOrUpdate<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>): this;
    /**
     * @override
     * @param {object} data for update or create
     * @returns {this} this
     */
    createOrUpdate<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>): this;
    /**
     * @override
     * @param {object} data for create
     * @returns {this} this
     */
    createOrSelect<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>): this;
    /**
     * @override
     * @param {object} data for update or create
     * @returns {this} this
     */
    insertOrSelect<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>): this;
    /**
     *
     * @override
     * @param {object} data create not exists data
     * @returns {this} this
     */
    createNotExists<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>): this;
    /**
     *
     * @override
     * @param {object} data create not exists data
     * @returns {this} this this
     */
    insertNotExists<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>): this;
    /**
     * @override
     * @param {Record<string,any>[]} data create multiple data
     * @returns {this} this this
     */
    createMultiple<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>[]): this;
    /**
     *
     * @override
     * @param {Record<string,any>[]} data create multiple data
     * @returns {this} this
     */
    createMany<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>[]): this;
    /**
     *
     * @override
     * @param {Record<string,any>[]} data create multiple data
     * @returns {this} this
     */
    insertMultiple<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>[]): this;
    /**
     *
     * @override
     * @param {Record<string,any>[]} data create multiple data
     * @returns {this} this
     */
    insertMany<K extends T.ColumnKeys<this>, C extends T.ColumnOptions<this>>(data: T.InsertInput<K, C>[]): this;
    /**
     * The 'getSchemaModel' method is used get a schema model
     * @returns {Record<string, Blueprint> | null} Record<string, Blueprint> | null
     */
    getSchemaModel(): Record<string, Blueprint> | null;
    /**
     * The 'validation' method is used validate the column by validating
     * @param {ValidateSchema} schema
     * @returns {this} this
     */
    validation(schema?: TValidateSchema): this;
    /**
     * The 'bindPattern' method is used to covert column relate with pattern
     * @param {string} column
     * @returns {string} return table.column
     */
    bindPattern(column: string): string;
    /**
     * @override
     * @returns {Promise<Record<string,any> | any[] | null | undefined>}
     */
    save({ waitMs }?: {
        waitMs?: number | undefined;
    }): Promise<T.InsertResult<this> | T.InsertManyResult<this> | T.InsertNotExistsResult<this> | T.UpdateResult<this> | T.UpdateManyResult<this> | null | undefined>;
    /**
     *
     * @override
     * @param {number} rows number of rows
     * @param {Function} callback function will be called data and index
     * @returns {promise<void>}
     */
    faker<K>(rows: number, callback?: (results: T.Result<this, K>, index: number) => T.Result<this, K>): Promise<void>;
    /**
     * The 'Sync' method is used to check for create or update table or columns with your schema in your model.
     * @type     {object}  options
     * @property {boolean} options.force - forec always check all columns if not exists will be created
     * @property {boolean} options.log   - show log execution with sql statements
     * @property {boolean} options.foreign - check when has a foreign keys will be created
     * @property {boolean} options.changed - check when column is changed attribute will be change attribute
     * @property {boolean} options.index - add index to column
     * @returns {Promise<void>}
     */
    sync({ force, foreign, changed, index, }?: {
        force?: boolean | undefined;
        foreign?: boolean | undefined;
        changed?: boolean | undefined;
        index?: boolean | undefined;
    }): Promise<void>;
    /**
     * Builds model templates for CLI generation.
     *
     * @async
     * @function buildModelTemplate
     * @param {Object} [options={}] - The build options.
     * @param {boolean} [options.decorator] - Whether to include decorators in the generated model template.
     * @param {string} [options.env] - Environment name to load configuration from.
     * @returns {Promise<Array<{ model: string, template: string }>>}
     */
    buildModelTemplate({ decorator, env, }?: {
        decorator?: boolean;
        env?: string;
    }): Promise<{
        model: string;
        template: string;
    }[]>;
    protected _valuePattern(column: string): string;
    protected _classToTableName(className?: string | null, { singular }?: {
        singular?: boolean | undefined;
    }): string;
    private _makeTableName;
    private _handleSoftDelete;
    private _prepareQueryPipeline;
    private _ensureRelationOwnerKeysSelected;
    private _handleGlobalScope;
    /**
     * @override
     * @return {this}
     */
    protected _handleSelect(): this;
    /**
     *
     * generate sql statements
     * @override
     */
    protected _queryBuilder(): any;
    private _runBefore;
    private _runAfter;
    private _validateSchema;
    private _getCache;
    private _setCache;
    private _execute;
    private _pagination;
    private _returnEmpty;
    private _returnResult;
    private _queryUpdateModel;
    private _queryInsertModel;
    private _queryInsertMultipleModel;
    private _insertNotExistsModel;
    private _insertModel;
    private _insertMultipleModel;
    private _updateOrInsertModel;
    private _insertOrSelectModel;
    private _updateModel;
    private _assertError;
    disabledRetry(): this;
    private _checkSchemaOrNextError;
    private _stoppedRetry;
    private _observer;
    private _mapReflectMetadata;
    private _guardWhereCondition;
    private _isModel;
    private _getBlueprintByColumn;
    private _handleJoinModel;
    private _formatedInputData;
    private _initialModel;
}
export { Model };
export default Model;
