tspace-mysql
Version:
Tspace MySQL is a promise-based ORM for Node.js, designed with modern TypeScript and providing type safety for schema databases.
1,319 lines • 100 kB
TypeScript
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 {
* cons