@athenna/database
Advanced tools
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| declare const _default: { | ||
| container_name: string; | ||
| image: string; | ||
| ports: string[]; | ||
| environment: { | ||
| MONGO_INITDB_ROOT_USERNAME: string; | ||
| MONGO_INITDB_ROOT_PASSWORD: string; | ||
| }; | ||
| }; | ||
| export default _default; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export default { | ||
| container_name: 'athenna_mongo', | ||
| image: 'mongo', | ||
| ports: ['27017:27017'], | ||
| environment: { | ||
| MONGO_INITDB_ROOT_USERNAME: 'root', | ||
| MONGO_INITDB_ROOT_PASSWORD: 'root' | ||
| } | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| declare const _default: { | ||
| container_name: string; | ||
| image: string; | ||
| ports: string[]; | ||
| environment: { | ||
| MYSQL_DATABASE: string; | ||
| MYSQL_ROOT_PASSWORD: string; | ||
| MYSQL_ALLOW_EMPTY_PASSWORD: string; | ||
| }; | ||
| }; | ||
| export default _default; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export default { | ||
| container_name: 'athenna_mysql', | ||
| image: 'mysql', | ||
| ports: ['3306:3306'], | ||
| environment: { | ||
| MYSQL_DATABASE: 'athenna', | ||
| MYSQL_ROOT_PASSWORD: 'root', | ||
| MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' | ||
| } | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| declare const _default: { | ||
| container_name: string; | ||
| image: string; | ||
| ports: string[]; | ||
| environment: { | ||
| POSTGRES_DB: string; | ||
| POSTGRES_USER: string; | ||
| POSTGRES_PASSWORD: string; | ||
| POSTGRES_ROOT_PASSWORD: string; | ||
| }; | ||
| }; | ||
| export default _default; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export default { | ||
| container_name: 'athenna_postgres', | ||
| image: 'postgres', | ||
| ports: ['5432:5432'], | ||
| environment: { | ||
| POSTGRES_DB: 'athenna', | ||
| POSTGRES_USER: 'root', | ||
| POSTGRES_PASSWORD: 'root', | ||
| POSTGRES_ROOT_PASSWORD: 'root' | ||
| } | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { BaseConfigurer } from '@athenna/artisan'; | ||
| export default class DatabaseConfigurer extends BaseConfigurer { | ||
| configure(): Promise<void>; | ||
| private databasePath; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { relative } from 'node:path'; | ||
| import { BaseConfigurer } from '@athenna/artisan'; | ||
| import { File, Module, Parser, Path } from '@athenna/common'; | ||
| export default class DatabaseConfigurer extends BaseConfigurer { | ||
| async configure() { | ||
| const connection = await this.prompt.list('What will be your default connection?', ['mysql', 'postgres', 'sqlite', 'mongo']); | ||
| const ext = Path.ext(); | ||
| const task = this.logger.task(); | ||
| task.addPromise(`Create database.${ext} configuration file`, () => { | ||
| return new File(`./database`).copy(Path.config(`database.${ext}`)); | ||
| }); | ||
| task.addPromise('Update commands of .athennarc.json', () => { | ||
| return this.rc | ||
| .setTo('commands', 'make:model', '@athenna/database/commands/MakeModelCommand') | ||
| .setTo('commands', 'make:seeder', '@athenna/database/commands/MakeSeederCommand') | ||
| .setTo('commands', 'make:migration', '@athenna/database/commands/MakeMigrationCommand') | ||
| .setTo('commands', 'make:crud', { | ||
| path: '@athenna/database/commands/MakeCrudCommand', | ||
| fileCase: 'toDotCase' | ||
| }) | ||
| .setTo('commands', 'db:fresh', { | ||
| path: '@athenna/database/commands/DbFreshCommand', | ||
| loadApp: true, | ||
| loadAllCommands: true | ||
| }) | ||
| .setTo('commands', 'db:seed', { | ||
| path: '@athenna/database/commands/DbSeedCommand', | ||
| loadApp: true | ||
| }) | ||
| .setTo('commands', 'db:wipe', { | ||
| path: '@athenna/database/commands/DbWipeCommand', | ||
| loadApp: true | ||
| }) | ||
| .setTo('commands', 'migration:run', { | ||
| path: '@athenna/database/commands/MigrationRunCommand', | ||
| loadApp: true | ||
| }) | ||
| .setTo('commands', 'migration:revert', { | ||
| path: '@athenna/database/commands/MigrationRevertCommand', | ||
| loadApp: true | ||
| }) | ||
| .save(); | ||
| }); | ||
| task.addPromise('Update templates of .athennarc.json', () => { | ||
| return this.rc | ||
| .setTo('templates', 'model', 'node_modules/@athenna/database/templates/model.edge') | ||
| .setTo('templates', 'seeder', 'node_modules/@athenna/database/templates/seeder.edge') | ||
| .setTo('templates', 'migration', 'node_modules/@athenna/database/templates/migration.edge') | ||
| .setTo('templates', 'crud-model', 'node_modules/@athenna/database/templates/crud-model.edge') | ||
| .setTo('templates', 'crud-migration', 'node_modules/@athenna/database/templates/crud-migration.edge') | ||
| .setTo('templates', 'crud-service', 'node_modules/@athenna/database/templates/crud-service.edge') | ||
| .setTo('templates', 'crud-controller', 'node_modules/@athenna/database/templates/crud-controller.edge') | ||
| .setTo('templates', 'crud-service-test', 'node_modules/@athenna/database/templates/crud-service-test.edge') | ||
| .setTo('templates', 'crud-controller-test', 'node_modules/@athenna/database/templates/crud-controller-test.edge') | ||
| .save(); | ||
| }); | ||
| task.addPromise('Update providers of .athennarc.json', () => { | ||
| return this.rc | ||
| .pushTo('providers', '@athenna/database/providers/DatabaseProvider') | ||
| .save(); | ||
| }); | ||
| task.addPromise('Update .env, .env.test and .env.example', () => { | ||
| let envs = ''; | ||
| switch (connection) { | ||
| case 'mongo': | ||
| envs = | ||
| '\nDB_CONNECTION=mongo\n' + | ||
| 'DB_DEBUG=false\n' + | ||
| 'DB_URL=mongodb://root:root@localhost:27017/admin\n'; | ||
| break; | ||
| case 'sqlite': | ||
| envs = | ||
| '\nDB_CONNECTION=sqlite\n' + | ||
| 'DB_DEBUG=false\n' + | ||
| `DB_FILENAME=${this.databasePath()}/sqlite.db\n`; | ||
| break; | ||
| default: | ||
| // eslint-disable-next-line no-case-declarations | ||
| const ports = { | ||
| mysql: 3306, | ||
| postgres: 5432 | ||
| }; | ||
| envs = | ||
| `\nDB_CONNECTION=${connection}\n` + | ||
| 'DB_HOST=localhost\n' + | ||
| `DB_PORT=${ports[connection]}\n` + | ||
| 'DB_DEBUG=false\n' + | ||
| 'DB_USERNAME=root\n' + | ||
| 'DB_PASSWORD=root\n' + | ||
| 'DB_DATABASE=athenna\n'; | ||
| } | ||
| const testEnvs = envs.replace(`DB_CONNECTION=${connection}`, 'DB_CONNECTION=fake'); | ||
| return new File(Path.pwd('.env'), '') | ||
| .append(envs) | ||
| .then(() => new File(Path.pwd('.env.test'), '').append(testEnvs)) | ||
| .then(() => new File(Path.pwd('.env.example'), '').append(envs)); | ||
| }); | ||
| if (connection !== 'sqlite') { | ||
| task.addPromise('Add service to docker-compose.yml file', async () => { | ||
| const hasDockerCompose = await File.exists(Path.pwd('docker-compose.yml')); | ||
| if (hasDockerCompose) { | ||
| const docker = await new File(Path.pwd('docker-compose.yml')).getContentAsYaml(); | ||
| docker.services[connection] = await Module.get(import(`./docker/${connection}/service.ts`)); | ||
| return new File(Path.pwd('docker-compose.yml')).setContent(Parser.objectToYamlString(docker)); | ||
| } | ||
| return new File(`./docker/${connection}/file.yml`).copy(Path.pwd('docker-compose.yml')); | ||
| }); | ||
| } | ||
| const libraries = { | ||
| mysql: ['knex', 'mysql2'], | ||
| postgres: ['knex', 'pg'], | ||
| sqlite: ['knex', 'better-sqlite3'], | ||
| mongo: ['mongoose'] | ||
| }; | ||
| task.addPromise(`Install ${libraries[connection].join(', ')} libraries`, () => { | ||
| return this.npm.install(libraries[connection]); | ||
| }); | ||
| await task.run(); | ||
| console.log(); | ||
| this.logger.success('Successfully configured ({dim,yellow} @athenna/database) library'); | ||
| if (connection !== 'sqlite') { | ||
| this.logger | ||
| .instruction() | ||
| .head('Run following commands to get started:') | ||
| .add(`docker-compose up -d`) | ||
| .render(); | ||
| } | ||
| } | ||
| databasePath() { | ||
| return relative(Path.pwd(), Path.database()).replace(/\\/g, '/'); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { BaseCommand } from '@athenna/artisan'; | ||
| export declare class DbWipeCommand extends BaseCommand { | ||
| connection: string; | ||
| withSeeders: boolean; | ||
| static signature(): string; | ||
| static description(): string; | ||
| handle(): Promise<void>; | ||
| private getConfig; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
| var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
| else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
| return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
| }; | ||
| var __metadata = (this && this.__metadata) || function (k, v) { | ||
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
| }; | ||
| import { Artisan, BaseCommand, Option } from '@athenna/artisan'; | ||
| export class DbWipeCommand extends BaseCommand { | ||
| static signature() { | ||
| return 'db:fresh'; | ||
| } | ||
| static description() { | ||
| return 'Drop all the tables of your database and run migrations again.'; | ||
| } | ||
| async handle() { | ||
| await Artisan.call(`db:wipe --connection ${this.connection}`); | ||
| console.log(); | ||
| if (this.getConfig('driver') !== 'mongo') { | ||
| await Artisan.call(`migration:run --connection ${this.connection}`); | ||
| } | ||
| if (this.withSeeders) { | ||
| console.log(); | ||
| await Artisan.call(`db:seed --connection ${this.connection}`); | ||
| } | ||
| } | ||
| getConfig(name, defaultValue) { | ||
| return Config.get(`database.connections.${this.connection === 'default' | ||
| ? Config.get('database.default') | ||
| : this.connection}.${name}`, defaultValue); | ||
| } | ||
| } | ||
| __decorate([ | ||
| Option({ | ||
| default: 'default', | ||
| signature: '-c, --connection <connection>', | ||
| description: 'Set the the database connection.' | ||
| }), | ||
| __metadata("design:type", String) | ||
| ], DbWipeCommand.prototype, "connection", void 0); | ||
| __decorate([ | ||
| Option({ | ||
| default: false, | ||
| signature: '--with-seeders', | ||
| description: 'Run seeders at the end.' | ||
| }), | ||
| __metadata("design:type", Boolean) | ||
| ], DbWipeCommand.prototype, "withSeeders", void 0); |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { BaseCommand } from '@athenna/artisan'; | ||
| export declare class DbSeedCommand extends BaseCommand { | ||
| classes: string[]; | ||
| connection: string; | ||
| static signature(): string; | ||
| static description(): string; | ||
| handle(): Promise<void>; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
| var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
| else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
| return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
| }; | ||
| var __metadata = (this && this.__metadata) || function (k, v) { | ||
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
| }; | ||
| import { Database } from '#src/facades/Database'; | ||
| import { BaseCommand, Option } from '@athenna/artisan'; | ||
| export class DbSeedCommand extends BaseCommand { | ||
| static signature() { | ||
| return 'db:seed'; | ||
| } | ||
| static description() { | ||
| return 'Run your application seeders.'; | ||
| } | ||
| async handle() { | ||
| this.logger.simple('({bold,green} [ SEEDING DATABASE ])\n'); | ||
| const task = this.logger.task(); | ||
| const DB = Database.connection(this.connection); | ||
| await DB.runSeeders({ task, classes: this.classes }); | ||
| await task | ||
| .run() | ||
| .then(async () => { | ||
| const dbName = await DB.getCurrentDatabase(); | ||
| console.log(); | ||
| this.logger.success(`Database ({yellow} "${dbName}") successfully seeded.`); | ||
| }) | ||
| .finally(() => DB.close()); | ||
| } | ||
| } | ||
| __decorate([ | ||
| Option({ | ||
| default: [], | ||
| signature: '--classes <classes...>', | ||
| description: 'Specify the classes names that should run.' | ||
| }), | ||
| __metadata("design:type", Array) | ||
| ], DbSeedCommand.prototype, "classes", void 0); | ||
| __decorate([ | ||
| Option({ | ||
| default: 'default', | ||
| signature: '-c, --connection <connection>', | ||
| description: 'Set the the database connection.' | ||
| }), | ||
| __metadata("design:type", String) | ||
| ], DbSeedCommand.prototype, "connection", void 0); |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { BaseCommand } from '@athenna/artisan'; | ||
| export declare class DbWipeCommand extends BaseCommand { | ||
| connection: string; | ||
| static signature(): string; | ||
| static description(): string; | ||
| handle(): Promise<void>; | ||
| private getConfig; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
| var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
| else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
| return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
| }; | ||
| var __metadata = (this && this.__metadata) || function (k, v) { | ||
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
| }; | ||
| import { Database } from '#src/facades/Database'; | ||
| import { BaseCommand, Option } from '@athenna/artisan'; | ||
| export class DbWipeCommand extends BaseCommand { | ||
| static signature() { | ||
| return 'db:wipe'; | ||
| } | ||
| static description() { | ||
| return 'Drop all the tables of your database.'; | ||
| } | ||
| async handle() { | ||
| this.logger.simple('({bold,green} [ WIPING DATABASE ])\n'); | ||
| const task = this.logger.task(); | ||
| const DB = Database.connection(this.connection); | ||
| if (this.getConfig('driver') === 'mongo') { | ||
| task.addPromise('Dropping all database tables', async () => { | ||
| const tables = await DB.getTables(); | ||
| return tables.athenna.concurrently(table => DB.dropTable(table)); | ||
| }); | ||
| } | ||
| else { | ||
| const migrationsTable = this.getConfig('migrations.tableName', 'migrations'); | ||
| task.addPromise('Reverting migrations', () => DB.revertMigrations()); | ||
| task.addPromise('Drop migrations table', () => DB.dropTable(migrationsTable)); | ||
| } | ||
| await task | ||
| .run() | ||
| .then(async () => { | ||
| const dbName = await DB.getCurrentDatabase(); | ||
| console.log(); | ||
| this.logger.success(`Database ({yellow} "${dbName}") successfully wiped.`); | ||
| }) | ||
| .finally(() => DB.close()); | ||
| } | ||
| getConfig(name, defaultValue) { | ||
| return Config.get(`database.connections.${this.connection === 'default' | ||
| ? Config.get('database.default') | ||
| : this.connection}.${name}`, defaultValue); | ||
| } | ||
| } | ||
| __decorate([ | ||
| Option({ | ||
| default: 'default', | ||
| signature: '-c, --connection <connection>', | ||
| description: 'Set the the database connection.' | ||
| }), | ||
| __metadata("design:type", String) | ||
| ], DbWipeCommand.prototype, "connection", void 0); |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { BaseCommand } from '@athenna/artisan'; | ||
| export declare class MakeCrudCommand extends BaseCommand { | ||
| name: string; | ||
| namePascal: string; | ||
| nameLower: string; | ||
| isMongo: boolean; | ||
| properties: any[]; | ||
| static signature(): string; | ||
| static description(): string; | ||
| cleanGenerator(): void; | ||
| toCase(value: string): any; | ||
| handle(): Promise<void>; | ||
| makeModel(): Promise<void>; | ||
| makeMigration(): Promise<void>; | ||
| makeController(): Promise<void>; | ||
| addRoutes(): Promise<void>; | ||
| makeService(): Promise<void>; | ||
| makeControllerTest(): Promise<void>; | ||
| makeServiceTest(): Promise<void>; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
| var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
| else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
| return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
| }; | ||
| var __metadata = (this && this.__metadata) || function (k, v) { | ||
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
| }; | ||
| import { sep } from 'node:path'; | ||
| import { Json, Path, File, String } from '@athenna/common'; | ||
| import { BaseCommand, Option, Argument, Generator } from '@athenna/artisan'; | ||
| export class MakeCrudCommand extends BaseCommand { | ||
| constructor() { | ||
| super(...arguments); | ||
| this.properties = []; | ||
| } | ||
| static signature() { | ||
| return 'make:crud'; | ||
| } | ||
| static description() { | ||
| return 'Make a new CRUD in your application.'; | ||
| } | ||
| cleanGenerator() { | ||
| this.generator = new Generator(); | ||
| } | ||
| toCase(value) { | ||
| const fileCase = Config.get('rc.commands.make:crud.fileCase', 'toPascalCase'); | ||
| return String[fileCase](value); | ||
| } | ||
| async handle() { | ||
| this.logger.simple('({bold,green} [ MAKING CRUD ])\n'); | ||
| this.namePascal = String.toPascalCase(this.name); | ||
| this.nameLower = this.name.toLowerCase(); | ||
| const addId = await this.prompt.confirm(`Do you want to add the ${this.paint.yellow('"id"')} property?`); | ||
| if (addId) { | ||
| this.properties.push({ name: 'id', type: 'increments', custom: false }); | ||
| } | ||
| const addTimestamps = await this.prompt.confirm(`Does your CRUD need ${this.paint.yellow('"createdAt/updateAt"')} properties?`); | ||
| const addSoftDelete = await this.prompt.confirm(`Does your CRUD needs ${this.paint.yellow('"deletedAt"')} property? (Soft Delete)`); | ||
| let addMoreProps = await this.prompt.confirm('Do you want to add more properties to your CRUD?'); | ||
| while (addMoreProps) { | ||
| const name = await this.prompt.input('What will be the name of your property?'); | ||
| const type = await this.prompt.list('What will be the type of your property?', ['string', 'number', 'boolean', 'Date']); | ||
| const options = await this.prompt.checkbox('Select the options that fits your property:', [ | ||
| 'isPrimary', | ||
| 'isUnique', | ||
| 'isHidden', | ||
| 'notNullable', | ||
| 'isIndex', | ||
| 'isSparse' | ||
| ]); | ||
| const optionsObj = {}; | ||
| options.forEach(option => (optionsObj[option] = true)); | ||
| this.properties.push({ name, type, custom: true, ...optionsObj }); | ||
| addMoreProps = await this.prompt.confirm('Do you want to add more properties?'); | ||
| } | ||
| if (addTimestamps) { | ||
| this.properties.push({ | ||
| name: 'createdAt', | ||
| type: 'Date', | ||
| custom: false, | ||
| isCreateDate: true | ||
| }); | ||
| this.properties.push({ | ||
| name: 'updatedAt', | ||
| type: 'Date', | ||
| custom: false, | ||
| isUpdateDate: true | ||
| }); | ||
| } | ||
| if (addSoftDelete) { | ||
| this.properties.push({ | ||
| name: 'deletedAt', | ||
| type: 'Date', | ||
| custom: false, | ||
| isDeleteDate: true | ||
| }); | ||
| } | ||
| console.log(); | ||
| const task = this.logger.task(); | ||
| if (Config.get('rc.commands.make:crud.model.enabled', true)) { | ||
| task.addPromise('Creating model', () => this.makeModel()); | ||
| } | ||
| if (!this.isMongo && | ||
| Config.get('rc.commands.make:crud.migration.enabled', true)) { | ||
| task.addPromise('Creating migration', () => this.makeMigration()); | ||
| } | ||
| if (Config.get('rc.commands.make:crud.controller.enabled', true)) { | ||
| task.addPromise('Creating controller', () => this.makeController()); | ||
| task.addPromise('Adding CRUD routes', () => this.addRoutes()); | ||
| } | ||
| if (Config.get('rc.commands.make:crud.service.enabled', true)) { | ||
| task.addPromise('Creating service', () => this.makeService()); | ||
| } | ||
| if (Config.get('rc.commands.make:crud.controller-test.enabled', true)) { | ||
| task.addPromise('Creating e2e tests for controller', () => this.makeControllerTest()); | ||
| } | ||
| if (Config.get('rc.commands.make:crud.service-test.enabled', true)) { | ||
| task.addPromise('Creating unitary tests for service', () => this.makeServiceTest()); | ||
| } | ||
| await task.run(); | ||
| console.log(); | ||
| this.logger.success(`CRUD ({yellow} "${this.name}") successfully created.`); | ||
| } | ||
| async makeModel() { | ||
| this.cleanGenerator(); | ||
| const destination = Config.get('rc.commands.make:crud.model.destination', Path.models()); | ||
| let properties = ''; | ||
| let definitions = ''; | ||
| this.properties.forEach((p, i) => { | ||
| const property = Json.copy(p); | ||
| let annotationProps = ''; | ||
| if (property.isPrimary) { | ||
| annotationProps += 'isPrimary: true, '; | ||
| } | ||
| if (property.isUnique) { | ||
| annotationProps += 'isUnique: true, '; | ||
| } | ||
| if (property.isHidden) { | ||
| annotationProps += 'isHidden: true, '; | ||
| } | ||
| if (property.notNullable) { | ||
| annotationProps += 'isNullable: false, '; | ||
| } | ||
| if (property.isIndex) { | ||
| annotationProps += 'isIndex: true, '; | ||
| } | ||
| if (property.isSparse) { | ||
| annotationProps += 'isSparse: true, '; | ||
| } | ||
| if (property.isCreateDate) { | ||
| annotationProps += 'isCreateDate: true, '; | ||
| } | ||
| if (property.isUpdateDate) { | ||
| annotationProps += 'isUpdateDate: true, '; | ||
| } | ||
| if (property.isDeleteDate) { | ||
| annotationProps += 'isDeleteDate: true, '; | ||
| } | ||
| if (property.type === 'increments') { | ||
| property.type = this.isMongo ? 'string' : 'number'; | ||
| } | ||
| if (annotationProps.length) { | ||
| properties += ` @Column({ ${annotationProps.slice(0, annotationProps.length - 2)} })\n public ${property.name}: ${property.type}`; | ||
| } | ||
| else { | ||
| properties += ` @Column()\n public ${property.name}: ${property.type}`; | ||
| } | ||
| const type = { | ||
| string: 'this.faker.string.sample()', | ||
| number: 'this.faker.number.int({ max: 10000000 })', | ||
| boolean: 'this.faker.datatype.boolean()', | ||
| Date: 'this.faker.date.anytime()' | ||
| }; | ||
| if (property.custom) { | ||
| definitions += ` ${property.name}: ${type[property.type]}`; | ||
| } | ||
| if (this.properties.length - 1 !== i) { | ||
| properties += '\n\n'; | ||
| if (definitions.length && property.custom) | ||
| definitions += ',\n'; | ||
| } | ||
| }); | ||
| await this.generator | ||
| .fileName(this.toCase(this.name)) | ||
| .destination(destination) | ||
| .template('crud-model') | ||
| .properties({ properties, definitions }) | ||
| .setNameProperties(true) | ||
| .make(); | ||
| const importPath = this.generator.getImportPath(); | ||
| await this.rc.pushTo('models', importPath).save(); | ||
| } | ||
| async makeMigration() { | ||
| this.cleanGenerator(); | ||
| const destination = Config.get('rc.commands.make:crud.migration.destination', Path.migrations()); | ||
| let properties = ''; | ||
| this.properties.forEach((property, i) => { | ||
| if (property.isCreateDate || property.isUpdateDate) { | ||
| if (properties.includes('builder.timestamps(true, true, true)')) { | ||
| return; | ||
| } | ||
| properties += ` builder.timestamps(true, true, true)${this.properties.length - 1 !== i ? '\n' : ''}`; | ||
| return; | ||
| } | ||
| switch (property.type) { | ||
| case 'increments': | ||
| properties += ` builder.increments('${property.name}')`; | ||
| break; | ||
| case 'string': | ||
| properties += ` builder.string('${property.name}')`; | ||
| break; | ||
| case 'boolean': | ||
| properties += ` builder.boolean('${property.name}')`; | ||
| break; | ||
| case 'number': | ||
| properties += ` builder.integer('${property.name}')`; | ||
| break; | ||
| case 'Date': | ||
| properties += ` builder.timestamp('${property.name}')`; | ||
| } | ||
| if (property.isPrimary) { | ||
| properties += '.primary()'; | ||
| } | ||
| if (property.isUnique) { | ||
| properties += '.unique()'; | ||
| } | ||
| if (!property.notNullable && property.type !== 'increments') { | ||
| properties += '.nullable()'; | ||
| } | ||
| if (property.isIndex) { | ||
| properties += '.index()'; | ||
| } | ||
| if (this.properties.length - 1 !== i) { | ||
| properties += '\n'; | ||
| } | ||
| }); | ||
| const tableName = String.pluralize(this.name); | ||
| const namePascal = String.toPascalCase(`Create_${tableName}_Table`); | ||
| let [date, time] = new Date().toISOString().split('T'); | ||
| date = date.replace(/-/g, '_'); | ||
| time = time.split('.')[0].replace(/:/g, ''); | ||
| await this.generator | ||
| .fileName(`${sep}${date}_${time}_create_${tableName}_table`) | ||
| .destination(destination) | ||
| .properties({ namePascal, properties, tableName }) | ||
| .template('crud-migration') | ||
| .setNameProperties(false) | ||
| .make(); | ||
| } | ||
| async makeController() { | ||
| this.cleanGenerator(); | ||
| const destination = Config.get('rc.commands.make:crud.controller.destination', Path.controllers()); | ||
| const serviceDest = Config.get('rc.commands.make:crud.service.destination', Path.services()); | ||
| let properties = ''; | ||
| this.properties | ||
| .filter(p => p.custom) | ||
| .forEach(p => { | ||
| properties += `'${p.name}', `; | ||
| }); | ||
| this.generator | ||
| .fileName(this.toCase(`${this.name}Controller`)) | ||
| .destination(destination) | ||
| .properties({ | ||
| properties: properties.slice(0, properties.length - 2), | ||
| serviceImportPath: new Generator() | ||
| .fileName(this.toCase(`${this.name}Service`)) | ||
| .destination(serviceDest) | ||
| .getImportPath(), | ||
| crudNamePascal: this.namePascal, | ||
| crudNameLower: this.nameLower | ||
| }) | ||
| .template('crud-controller') | ||
| .setNameProperties(true); | ||
| await this.generator.make(); | ||
| const importPath = this.generator.getImportPath(); | ||
| await this.rc.pushTo('controllers', importPath).save(); | ||
| } | ||
| async addRoutes() { | ||
| const routeFilePath = Config.get('rc.commands.make:crud.routeFilePath', Path.routes(`http.${Path.ext()}`)); | ||
| const path = `/${String.pluralize(this.nameLower)}`; | ||
| const controller = `${this.namePascal}Controller`; | ||
| let body = ''; | ||
| this.properties | ||
| .filter(p => p.custom) | ||
| .forEach(property => { | ||
| const type = { | ||
| string: 'string', | ||
| number: 'number', | ||
| boolean: 'boolean', | ||
| Date: 'string' | ||
| }; | ||
| body += `.body('${property.name}', { type: '${type[property.type]}' })`; | ||
| }); | ||
| const routeContent = ` | ||
| Route.get('${path}', '${controller}.index') | ||
| Route.post('${path}', '${controller}.store')${body} | ||
| Route.get('${path}/:id', '${controller}.show') | ||
| Route.put('${path}/:id', '${controller}.update')${body} | ||
| Route.delete('${path}/:id', '${controller}.delete') | ||
| \n`; | ||
| await new File(routeFilePath, `import { Route } from '@athenna/http'\n\n`).append(routeContent); | ||
| } | ||
| async makeService() { | ||
| this.cleanGenerator(); | ||
| const destination = Config.get('rc.commands.make:crud.service.destination', Path.services()); | ||
| const modelDest = Config.get('rc.commands.make:crud.model.destination', Path.models()); | ||
| let propertiesToUpdate = ''; | ||
| this.properties | ||
| .filter(p => p.custom) | ||
| .forEach(property => { | ||
| propertiesToUpdate += ` ${this.nameLower}.${property.name} = body.${property.name}\n`; | ||
| }); | ||
| await this.generator | ||
| .fileName(this.toCase(`${this.name}Service`)) | ||
| .destination(destination) | ||
| .properties({ | ||
| propertiesToUpdate, | ||
| idType: this.isMongo ? 'string' : 'number', | ||
| modelImportPath: new Generator() | ||
| .fileName(this.toCase(this.name)) | ||
| .destination(modelDest) | ||
| .getImportPath(), | ||
| crudNamePascal: this.namePascal, | ||
| crudNameLower: this.nameLower | ||
| }) | ||
| .template('crud-service') | ||
| .setNameProperties(true) | ||
| .make(); | ||
| const importPath = this.generator.getImportPath(); | ||
| await this.rc.pushTo('services', importPath).save(); | ||
| } | ||
| async makeControllerTest() { | ||
| this.cleanGenerator(); | ||
| const destination = Config.get('rc.commands.make:crud.controller-test.destination', Path.tests('e2e')); | ||
| const modelDest = Config.get('rc.commands.make:crud.model.destination', Path.models()); | ||
| let createBody = ''; | ||
| let updateBody = ''; | ||
| let showAssertBody = `id: ${this.nameLower}.id, `; | ||
| let createAssertBody = ''; | ||
| let updateAssertBody = `id: ${this.nameLower}.id, `; | ||
| this.properties | ||
| .filter(p => p.custom) | ||
| .forEach(property => { | ||
| const type = { | ||
| string: `'string'`, | ||
| number: 1, | ||
| boolean: true, | ||
| Date: 'new Date()' | ||
| }; | ||
| createBody += `${property.name}: ${type[property.type]}, `; | ||
| updateBody += `${property.name}: ${type[property.type]}, `; | ||
| showAssertBody += `${property.name}: ${type[property.type]}, `; | ||
| createAssertBody += `'${property.name}', `; | ||
| updateAssertBody += `${property.name}: ${type[property.type]}, `; | ||
| }); | ||
| await this.generator | ||
| .fileName(this.toCase(`${this.name}ControllerTest`)) | ||
| .destination(destination) | ||
| .properties({ | ||
| hasDeletedAt: this.properties.find(p => p.name === 'deletedAt'), | ||
| createBody: createBody.slice(0, createBody.length - 2), | ||
| updateBody: updateBody.slice(0, updateBody.length - 2), | ||
| showAssertBody: showAssertBody.slice(0, showAssertBody.length - 2), | ||
| createAssertBody: createAssertBody.slice(0, createAssertBody.length - 2), | ||
| updateAssertBody: updateAssertBody.slice(0, updateAssertBody.length - 2), | ||
| modelImportPath: new Generator() | ||
| .fileName(this.toCase(this.name)) | ||
| .destination(modelDest) | ||
| .getImportPath(), | ||
| crudNamePascal: this.namePascal, | ||
| crudNamePascalPlural: String.pluralize(this.namePascal), | ||
| crudNameLower: this.nameLower, | ||
| crudNameLowerPlural: String.pluralize(this.nameLower) | ||
| }) | ||
| .template('crud-controller-test') | ||
| .setNameProperties(true) | ||
| .make(); | ||
| } | ||
| async makeServiceTest() { | ||
| this.cleanGenerator(); | ||
| const destination = Config.get('rc.commands.make:crud.service-test.destination', Path.tests('unit')); | ||
| const modelDest = Config.get('rc.commands.make:crud.model.destination', Path.models()); | ||
| const serviceDest = Config.get('rc.commands.make:crud.service.destination', Path.services()); | ||
| let createBody = ''; | ||
| let updateBody = ''; | ||
| this.properties | ||
| .filter(p => p.custom) | ||
| .forEach(property => { | ||
| const type = { | ||
| string: `'string'`, | ||
| number: 1, | ||
| boolean: true, | ||
| Date: 'new Date()' | ||
| }; | ||
| createBody += `${property.name}: ${type[property.type]}, `; | ||
| updateBody += `${property.name}: ${type[property.type]}, `; | ||
| }); | ||
| await this.generator | ||
| .fileName(this.toCase(`${this.name}ServiceTest`)) | ||
| .destination(destination) | ||
| .properties({ | ||
| createBody: createBody.slice(0, createBody.length - 2), | ||
| updateBody: updateBody.slice(0, updateBody.length - 2), | ||
| modelImportPath: new Generator() | ||
| .fileName(this.toCase(this.name)) | ||
| .destination(modelDest) | ||
| .getImportPath(), | ||
| serviceImportPath: new Generator() | ||
| .fileName(this.toCase(`${this.name}Service`)) | ||
| .destination(serviceDest) | ||
| .getImportPath(), | ||
| crudNamePascal: this.namePascal, | ||
| crudNamePascalPlural: String.pluralize(this.namePascal), | ||
| crudNameLower: this.nameLower, | ||
| crudNameLowerPlural: String.pluralize(this.nameLower) | ||
| }) | ||
| .template('crud-service-test') | ||
| .setNameProperties(true) | ||
| .make(); | ||
| } | ||
| } | ||
| __decorate([ | ||
| Argument({ | ||
| description: 'The crud name.' | ||
| }), | ||
| __metadata("design:type", String) | ||
| ], MakeCrudCommand.prototype, "name", void 0); | ||
| __decorate([ | ||
| Option({ | ||
| default: false, | ||
| signature: '--mongo', | ||
| description: 'Define if CRUD will use Mongo as database. Migration will be skipped and "id" will be defined as string.' | ||
| }), | ||
| __metadata("design:type", Boolean) | ||
| ], MakeCrudCommand.prototype, "isMongo", void 0); |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { BaseCommand } from '@athenna/artisan'; | ||
| export declare class MakeMigrationCommand extends BaseCommand { | ||
| name: string; | ||
| static signature(): string; | ||
| static description(): string; | ||
| handle(): Promise<void>; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
| var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
| else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
| return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
| }; | ||
| var __metadata = (this && this.__metadata) || function (k, v) { | ||
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
| }; | ||
| import { sep } from 'node:path'; | ||
| import { Path, String } from '@athenna/common'; | ||
| import { BaseCommand, Argument } from '@athenna/artisan'; | ||
| export class MakeMigrationCommand extends BaseCommand { | ||
| static signature() { | ||
| return 'make:migration'; | ||
| } | ||
| static description() { | ||
| return 'Make a new migration file.'; | ||
| } | ||
| async handle() { | ||
| this.logger.simple('({bold,green} [ MAKING MIGRATION ])\n'); | ||
| const nameUp = this.name.toUpperCase(); | ||
| const nameCamel = String.toCamelCase(this.name); | ||
| const namePlural = String.pluralize(this.name); | ||
| const namePascal = String.toPascalCase(this.name); | ||
| const nameSnake = String.toSnakeCase(this.name); | ||
| const namePluralCamel = String.toCamelCase(String.pluralize(this.name)); | ||
| const namePluralPascal = String.toPascalCase(String.pluralize(this.name)); | ||
| const destination = Config.get('rc.commands.make:migration.destination', Path.migrations()); | ||
| const tableName = String.pluralize(namePascal | ||
| .replace('Migration', '') | ||
| .replace('Migrations', '') | ||
| .toLowerCase()); | ||
| let [date, time] = new Date().toISOString().split('T'); | ||
| date = date.replace(/-/g, '_'); | ||
| time = time.split('.')[0].replace(/:/g, ''); | ||
| const file = await this.generator | ||
| .fileName(`${sep}${date}_${time}_${nameSnake}`) | ||
| .destination(destination) | ||
| .properties({ | ||
| nameUp, | ||
| nameCamel, | ||
| namePlural, | ||
| namePascal, | ||
| namePluralCamel, | ||
| namePluralPascal, | ||
| tableName | ||
| }) | ||
| .template('migration') | ||
| .make(); | ||
| this.logger.success(`Migration ({yellow} "${file.name}") successfully created.`); | ||
| } | ||
| } | ||
| __decorate([ | ||
| Argument({ | ||
| description: 'The migration name.' | ||
| }), | ||
| __metadata("design:type", String) | ||
| ], MakeMigrationCommand.prototype, "name", void 0); |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { BaseCommand } from '@athenna/artisan'; | ||
| export declare class MakeModelCommand extends BaseCommand { | ||
| name: string; | ||
| static signature(): string; | ||
| static description(): string; | ||
| handle(): Promise<void>; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
| var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
| else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
| return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
| }; | ||
| var __metadata = (this && this.__metadata) || function (k, v) { | ||
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
| }; | ||
| import { Path } from '@athenna/common'; | ||
| import { BaseCommand, Argument } from '@athenna/artisan'; | ||
| export class MakeModelCommand extends BaseCommand { | ||
| static signature() { | ||
| return 'make:model'; | ||
| } | ||
| static description() { | ||
| return 'Make a new model file.'; | ||
| } | ||
| async handle() { | ||
| this.logger.simple('({bold,green} [ MAKING MODEL ])\n'); | ||
| const destination = Config.get('rc.commands.make:model.destination', Path.models()); | ||
| const file = await this.generator | ||
| .fileName(this.name) | ||
| .destination(destination) | ||
| .template('model') | ||
| .setNameProperties(true) | ||
| .make(); | ||
| this.logger.success(`Model ({yellow} "${file.name}") successfully created.`); | ||
| const importPath = this.generator.getImportPath(); | ||
| await this.rc.pushTo('models', importPath).save(); | ||
| this.logger.success(`Athenna RC updated: ({dim,yellow} [ models += "${importPath}" ])`); | ||
| } | ||
| } | ||
| __decorate([ | ||
| Argument({ | ||
| description: 'The model name.' | ||
| }), | ||
| __metadata("design:type", String) | ||
| ], MakeModelCommand.prototype, "name", void 0); |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { BaseCommand } from '@athenna/artisan'; | ||
| export declare class MakeSeederCommand extends BaseCommand { | ||
| name: string; | ||
| static signature(): string; | ||
| static description(): string; | ||
| handle(): Promise<void>; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
| var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
| else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
| return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
| }; | ||
| var __metadata = (this && this.__metadata) || function (k, v) { | ||
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
| }; | ||
| import { Path } from '@athenna/common'; | ||
| import { BaseCommand, Argument } from '@athenna/artisan'; | ||
| export class MakeSeederCommand extends BaseCommand { | ||
| static signature() { | ||
| return 'make:seeder'; | ||
| } | ||
| static description() { | ||
| return 'Make a new seeder file.'; | ||
| } | ||
| async handle() { | ||
| this.logger.simple('({bold,green} [ MAKING SEEDER ])\n'); | ||
| const destination = Config.get('rc.commands.make:seeder.destination', Path.seeders()); | ||
| const file = await this.generator | ||
| .fileName(this.name) | ||
| .destination(destination) | ||
| .template('seeder') | ||
| .setNameProperties(true) | ||
| .make(); | ||
| this.logger.success(`Seeder ({yellow} "${file.name}") successfully created.`); | ||
| } | ||
| } | ||
| __decorate([ | ||
| Argument({ | ||
| description: 'The seeder name.' | ||
| }), | ||
| __metadata("design:type", String) | ||
| ], MakeSeederCommand.prototype, "name", void 0); |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { BaseCommand } from '@athenna/artisan'; | ||
| export declare class MigrationRevertCommand extends BaseCommand { | ||
| connection: string; | ||
| static signature(): string; | ||
| static description(): string; | ||
| handle(): Promise<void>; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
| var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
| else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
| return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
| }; | ||
| var __metadata = (this && this.__metadata) || function (k, v) { | ||
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
| }; | ||
| import { Database } from '#src/facades/Database'; | ||
| import { BaseCommand, Option } from '@athenna/artisan'; | ||
| export class MigrationRevertCommand extends BaseCommand { | ||
| static signature() { | ||
| return 'migration:revert'; | ||
| } | ||
| static description() { | ||
| return 'Revert your application migrations.'; | ||
| } | ||
| async handle() { | ||
| this.logger.simple('({bold,green} [ REVERTING MIGRATIONS ])\n'); | ||
| if (Config.is(`database.connections.${this.connection}.driver`, 'mongo')) { | ||
| this.logger.warn(`Connection ({yellow} "${this.connection}") is using ({yellow} "mongo") driver and migrations revert will be skipped.`); | ||
| return; | ||
| } | ||
| const DB = Database.connection(this.connection); | ||
| await DB.revertMigrations() | ||
| .then(async () => { | ||
| const dbName = await DB.getCurrentDatabase(); | ||
| this.logger.success(`Successfully reverted migrations on ({yellow} "${dbName}") database.`); | ||
| }) | ||
| .finally(() => DB.close()); | ||
| } | ||
| } | ||
| __decorate([ | ||
| Option({ | ||
| default: 'default', | ||
| signature: '-c, --connection <connection>', | ||
| description: 'Set the the database connection.' | ||
| }), | ||
| __metadata("design:type", String) | ||
| ], MigrationRevertCommand.prototype, "connection", void 0); |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { BaseCommand } from '@athenna/artisan'; | ||
| export declare class MigrationRunCommand extends BaseCommand { | ||
| connection: string; | ||
| static signature(): string; | ||
| static description(): string; | ||
| handle(): Promise<void>; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
| var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; | ||
| if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); | ||
| else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; | ||
| return c > 3 && r && Object.defineProperty(target, key, r), r; | ||
| }; | ||
| var __metadata = (this && this.__metadata) || function (k, v) { | ||
| if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); | ||
| }; | ||
| import { Database } from '#src/facades/Database'; | ||
| import { BaseCommand, Option } from '@athenna/artisan'; | ||
| export class MigrationRunCommand extends BaseCommand { | ||
| static signature() { | ||
| return 'migration:run'; | ||
| } | ||
| static description() { | ||
| return 'Run your application migrations.'; | ||
| } | ||
| async handle() { | ||
| this.logger.simple('({bold,green} [ RUNNING MIGRATIONS ])\n'); | ||
| if (Config.is(`database.connections.${this.connection}.driver`, 'mongo')) { | ||
| this.logger.warn(`Connection ({yellow} "${this.connection}") is using ({yellow} "mongo") driver and migrations run will be skipped.`); | ||
| return; | ||
| } | ||
| const DB = Database.connection(this.connection); | ||
| await DB.runMigrations() | ||
| .then(async () => { | ||
| const dbName = await DB.getCurrentDatabase(); | ||
| this.logger.success(`Successfully ran migrations on ({yellow} "${dbName}") database.`); | ||
| }) | ||
| .finally(() => DB.close()); | ||
| } | ||
| } | ||
| __decorate([ | ||
| Option({ | ||
| default: 'default', | ||
| signature: '-c, --connection <connection>', | ||
| description: 'Set the the database connection.' | ||
| }), | ||
| __metadata("design:type", String) | ||
| ], MigrationRunCommand.prototype, "connection", void 0); |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export declare const COLUMNS_KEY = "database:columns:options"; | ||
| export declare const HAS_ONE_KEY = "database:hasOne:options"; | ||
| export declare const HAS_MANY_KEY = "database:hasMany:options"; | ||
| export declare const BELONGS_TO_KEY = "database:belongsTo:options"; | ||
| export declare const BELONGS_TO_MANY_KEY = "database:belongsToMany:options"; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export const COLUMNS_KEY = 'database:columns:options'; | ||
| export const HAS_ONE_KEY = 'database:hasOne:options'; | ||
| export const HAS_MANY_KEY = 'database:hasMany:options'; | ||
| export const BELONGS_TO_KEY = 'database:belongsTo:options'; | ||
| export const BELONGS_TO_MANY_KEY = 'database:belongsToMany:options'; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| /** | ||
| * Map the operations dictionary from an SQL Database | ||
| * to MongoDB operators. | ||
| */ | ||
| export declare const MONGO_OPERATIONS_DICTIONARY: { | ||
| '=': string; | ||
| '>': string; | ||
| '>=': string; | ||
| '<': string; | ||
| '<=': string; | ||
| '<>': string; | ||
| like: string; | ||
| ilike: string; | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| /** | ||
| * Map the operations dictionary from an SQL Database | ||
| * to MongoDB operators. | ||
| */ | ||
| export const MONGO_OPERATIONS_DICTIONARY = { | ||
| '=': '$match', | ||
| '>': '$gt', | ||
| '>=': '$gte', | ||
| '<': '$lt', | ||
| '<=': '$lte', | ||
| '<>': '$ne', | ||
| like: '$regex', | ||
| ilike: '$regex' | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| /** | ||
| * Symbol used to store the original value of a model. | ||
| */ | ||
| export declare const ORIGINAL_SYMBOL: unique symbol; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| /** | ||
| * Symbol used to store the original value of a model. | ||
| */ | ||
| export const ORIGINAL_SYMBOL = Symbol('BaseModel.original'); |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| /** | ||
| * All Knex methods that are protected by drivers that | ||
| * are dependent of Knex query builder. Every time that | ||
| * one of these methods are called, a new instance of query | ||
| * builder is created inside the Driver using Proxies. | ||
| */ | ||
| export declare const PROTECTED_QUERY_METHODS: string[]; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| /** | ||
| * All Knex methods that are protected by drivers that | ||
| * are dependent of Knex query builder. Every time that | ||
| * one of these methods are called, a new instance of query | ||
| * builder is created inside the Driver using Proxies. | ||
| */ | ||
| export const PROTECTED_QUERY_METHODS = [ | ||
| 'pluck', | ||
| 'insert', | ||
| 'update', | ||
| 'delete', | ||
| 'first', | ||
| 'min', | ||
| 'max', | ||
| 'sum', | ||
| 'sumDistinct', | ||
| 'avg', | ||
| 'avgDistinct', | ||
| 'count', | ||
| 'countDistinct', | ||
| 'increment', | ||
| 'decrement' | ||
| ]; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Macroable, type Collection, type PaginatedResponse, type PaginationOptions } from '@athenna/common'; | ||
| import type { Operations } from '#src/types/Operations'; | ||
| import type { Direction, ModelColumns } from '#src/types'; | ||
| import type { Driver as DriverImpl } from '#src/database/drivers/Driver'; | ||
| export declare class QueryBuilder<T = any, Driver extends DriverImpl = any> extends Macroable { | ||
| /** | ||
| * The drivers responsible for handling database operations. | ||
| */ | ||
| protected driver: Driver; | ||
| /** | ||
| * The initial table that the query is going to work with. | ||
| */ | ||
| protected tableName: string; | ||
| /** | ||
| * Creates a new instance of QueryBuilder. | ||
| */ | ||
| constructor(driver: Driver, tableName: string); | ||
| /** | ||
| * Return the client of driver. | ||
| */ | ||
| getClient(): any; | ||
| /** | ||
| * Return the query builder of driver. | ||
| */ | ||
| getQueryBuilder(): any; | ||
| /** | ||
| * Set the query builder of driver. | ||
| */ | ||
| setQueryBuilder(queryBuilder: any): this; | ||
| /** | ||
| * Return the driver of the query builder. | ||
| */ | ||
| getDriver(): Driver; | ||
| /** | ||
| * Set the driver of the query builder. | ||
| */ | ||
| setDriver(driver: any, tableName?: string): this; | ||
| /** | ||
| * Set the driver primary key that will be used | ||
| * when creating new data. | ||
| */ | ||
| setPrimaryKey(primaryKey: string): this; | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| avg(column: string | ModelColumns<T>): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| avgDistinct(column: string | ModelColumns<T>): Promise<string>; | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| max(column: string | ModelColumns<T>): Promise<string>; | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| min(column: string | ModelColumns<T>): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| sum(column: string | ModelColumns<T>): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| sumDistinct(column: string | ModelColumns<T>): Promise<string>; | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| increment(column: string | ModelColumns<T>): Promise<void>; | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| decrement(column: string | ModelColumns<T>): Promise<void>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| count(column?: string | ModelColumns<T>): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| countDistinct(column: string | ModelColumns<T>): Promise<string>; | ||
| /** | ||
| * Find a value in database or throw exception if undefined. | ||
| */ | ||
| findOrFail(): Promise<T>; | ||
| /** | ||
| * Return a single data or, if no results are found, | ||
| * execute the given closure. | ||
| */ | ||
| findOr(callback: () => Promise<T>): Promise<T>; | ||
| /** | ||
| * Find value in database but returns only the value of | ||
| * selected column directly. | ||
| */ | ||
| pluck<K extends keyof T = keyof T>(column: K): Promise<T[K]>; | ||
| /** | ||
| * Find many values in database but returns only the | ||
| * values of selected column directly. | ||
| */ | ||
| pluckMany<K extends keyof T = keyof T>(column: K): Promise<T[K][]>; | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| find(): Promise<T>; | ||
| /** | ||
| * Find a value in database and return as boolean. | ||
| */ | ||
| exists(): Promise<boolean>; | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| findMany(): Promise<T[]>; | ||
| /** | ||
| * Find many values in database and return as a Collection. | ||
| */ | ||
| collection(): Promise<Collection<T>>; | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| paginate(page?: PaginationOptions | number, limit?: number, resourceUrl?: string): Promise<PaginatedResponse>; | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| create(data?: Partial<T>): Promise<T>; | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| createMany(data?: Partial<T>[]): Promise<T[]>; | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| createOrUpdate(data?: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Update data in database. | ||
| */ | ||
| update(data: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Delete data in database. | ||
| */ | ||
| delete(): Promise<T | T[] | void>; | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw(sql: string, bindings?: any): import("knex").Knex.Raw<any>; | ||
| /** | ||
| * Set a new table to work with in query builder. | ||
| */ | ||
| table(tableName: string): this; | ||
| /** | ||
| * Executes the given closure when the first argument is true. | ||
| */ | ||
| when(criteria: any, closure: (query: this, criteriaValue: any) => any | Promise<any>): this; | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| dump(): this; | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| select(...columns: string[] | ModelColumns<T>[]): this; | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| selectRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| from(table: string): this; | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| fromRaw(sql: string, bindings?: any): this; | ||
| join(tableName: string): this; | ||
| join(tableName: string, column: string): this; | ||
| join(tableName: string, column1: string, column2: string): this; | ||
| join(tableName: string, column1: string, operation: Operations, column2: string): this; | ||
| leftJoin(tableName: string): this; | ||
| leftJoin(tableName: string, column: string): this; | ||
| leftJoin(tableName: string, column1: string, column2: string): this; | ||
| leftJoin(tableName: string, column1: string, operation: Operations, column2: string): this; | ||
| rightJoin(tableName: string): this; | ||
| rightJoin(tableName: string, column: string): this; | ||
| rightJoin(tableName: string, column1: string, column2: string): this; | ||
| rightJoin(tableName: string, column1: string, operation: Operations, column2: string): this; | ||
| crossJoin(tableName: string): this; | ||
| crossJoin(tableName: string, column: string): this; | ||
| crossJoin(tableName: string, column1: string, column2: string): this; | ||
| crossJoin(tableName: string, column1: string, operation: Operations, column2: string): this; | ||
| fullOuterJoin(tableName: string): this; | ||
| fullOuterJoin(tableName: string, column: string): this; | ||
| fullOuterJoin(tableName: string, column1: string, column2: string): this; | ||
| fullOuterJoin(tableName: string, column1: string, operation: Operations, column2: string): this; | ||
| leftOuterJoin(tableName: string): this; | ||
| leftOuterJoin(tableName: string, column: string): this; | ||
| leftOuterJoin(tableName: string, column1: string, column2: string): this; | ||
| leftOuterJoin(tableName: string, column1: string, operation: Operations, column2: string): this; | ||
| rightOuterJoin(tableName: string): this; | ||
| rightOuterJoin(tableName: string, column: string): this; | ||
| rightOuterJoin(tableName: string, column1: string, column2: string): this; | ||
| rightOuterJoin(tableName: string, column1: string, operation: Operations, column2: string): this; | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| joinRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| groupBy(...columns: string[] | ModelColumns<T>[]): this; | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| groupByRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a having statement in your query. | ||
| */ | ||
| having(column: string | ModelColumns<T>, operation?: any | Operations, value?: any): this; | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| havingRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| havingExists(closure: (query: Driver) => void): this; | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| havingNotExists(closure: (query: Driver) => void): this; | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| havingIn(column: string | ModelColumns<T>, values: any[]): this; | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| havingNotIn(column: string | ModelColumns<T>, values: any[]): this; | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| havingBetween(column: string | ModelColumns<T>, values: [any, any]): this; | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| havingNotBetween(column: string | ModelColumns<T>, values: [any, any]): this; | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| havingNull(column: string | ModelColumns<T>): this; | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| havingNotNull(column: string | ModelColumns<T>): this; | ||
| /** | ||
| * Set an or having statement in your query. | ||
| */ | ||
| orHaving(column: string | ModelColumns<T>, operation?: any | Operations, value?: any): this; | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| orHavingRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| orHavingExists(closure: (query: Driver) => void): this; | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| orHavingNotExists(closure: (query: Driver) => void): this; | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| orHavingIn(column: string | ModelColumns<T>, values: any[]): this; | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| orHavingNotIn(column: string | ModelColumns<T>, values: any[]): this; | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| orHavingBetween(column: string | ModelColumns<T>, values: [any, any]): this; | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| orHavingNotBetween(column: string | ModelColumns<T>, values: [any, any]): this; | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| orHavingNull(column: string | ModelColumns<T>): this; | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| orHavingNotNull(column: string | ModelColumns<T>): this; | ||
| where(statement: (query: this) => void): this; | ||
| where(statement: Partial<T>): this; | ||
| where(statement: Record<string, any>): this; | ||
| where(key: string | ModelColumns<T>, value: any): this; | ||
| where(key: string | ModelColumns<T>, operation: Operations, value: any): this; | ||
| whereNot(statement: (query: this) => void): this; | ||
| whereNot(statement: Partial<T>): this; | ||
| whereNot(statement: Record<string, any>): this; | ||
| whereNot(key: string | ModelColumns<T>, value: any): this; | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| whereRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| whereExists(closure: (query: Driver) => void): this; | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| whereNotExists(closure: (query: Driver) => void): this; | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| whereLike(column: string | ModelColumns<T>, value: any): this; | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| whereILike(column: string | ModelColumns<T>, value: any): this; | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| whereIn(column: string | ModelColumns<T>, values: any[]): this; | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| whereNotIn(column: string | ModelColumns<T>, values: any[]): this; | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| whereBetween(column: string | ModelColumns<T>, values: [any, any]): this; | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| whereNotBetween(column: string | ModelColumns<T>, values: [any, any]): this; | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| whereNull(column: string | ModelColumns<T>): this; | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| whereNotNull(column: string | ModelColumns<T>): this; | ||
| orWhere(statement: (query: this) => void): this; | ||
| orWhere(statement: Partial<T>): this; | ||
| orWhere(statement: Record<string, any>): this; | ||
| orWhere(key: string | ModelColumns<T>, value: any): this; | ||
| orWhere(key: string | ModelColumns<T>, operation: Operations, value: any): this; | ||
| orWhereNot(statement: (query: this) => void): this; | ||
| orWhereNot(statement: Partial<T>): this; | ||
| orWhereNot(statement: Record<string, any>): this; | ||
| orWhereNot(key: string | ModelColumns<T>, value: any): this; | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| */ | ||
| orWhereRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| orWhereExists(closure: (query: Driver) => void): this; | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| orWhereNotExists(closure: (query: Driver) => void): this; | ||
| orWhereLike(statement: Partial<T>): this; | ||
| orWhereLike(statement: Record<string, any>): this; | ||
| orWhereLike(key: string | ModelColumns<T>, value: any): this; | ||
| orWhereILike(statement: Partial<T>): this; | ||
| orWhereILike(statement: Record<string, any>): this; | ||
| orWhereILike(key: string | ModelColumns<T>, value: any): this; | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| orWhereIn(column: string | ModelColumns<T>, values: any[]): this; | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| orWhereNotIn(column: string | ModelColumns<T>, values: any[]): this; | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| orWhereBetween(column: string | ModelColumns<T>, values: [any, any]): this; | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| orWhereNotBetween(column: string | ModelColumns<T>, values: [any, any]): this; | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| orWhereNull(column: string | ModelColumns<T>): this; | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| orWhereNotNull(column: string | ModelColumns<T>): this; | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| orderBy(column: string | ModelColumns<T>, direction?: Direction): this; | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| orderByRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| latest(column?: string | ModelColumns<T>): this; | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| oldest(column?: string | ModelColumns<T>): this; | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| offset(number: number): this; | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| limit(number: number): this; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Macroable } from '@athenna/common'; | ||
| export class QueryBuilder extends Macroable { | ||
| /** | ||
| * Creates a new instance of QueryBuilder. | ||
| */ | ||
| constructor(driver, tableName) { | ||
| super(); | ||
| this.driver = driver; | ||
| this.tableName = tableName; | ||
| this.driver.table(tableName); | ||
| } | ||
| /** | ||
| * Return the client of driver. | ||
| */ | ||
| getClient() { | ||
| return this.driver.getClient(); | ||
| } | ||
| /** | ||
| * Return the query builder of driver. | ||
| */ | ||
| getQueryBuilder() { | ||
| return this.driver.getQueryBuilder(); | ||
| } | ||
| /** | ||
| * Set the query builder of driver. | ||
| */ | ||
| setQueryBuilder(queryBuilder) { | ||
| this.driver.setQueryBuilder(queryBuilder, { useSetQB: true }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Return the driver of the query builder. | ||
| */ | ||
| getDriver() { | ||
| return this.driver; | ||
| } | ||
| /** | ||
| * Set the driver of the query builder. | ||
| */ | ||
| setDriver(driver, tableName) { | ||
| this.driver = driver; | ||
| this.driver.table(tableName || this.tableName); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the driver primary key that will be used | ||
| * when creating new data. | ||
| */ | ||
| setPrimaryKey(primaryKey) { | ||
| this.driver.setPrimaryKey(primaryKey); | ||
| return this; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| async avg(column) { | ||
| return this.driver.avg(column); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| async avgDistinct(column) { | ||
| return this.driver.avgDistinct(column); | ||
| } | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| async max(column) { | ||
| return this.driver.max(column); | ||
| } | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| async min(column) { | ||
| return this.driver.min(column); | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| async sum(column) { | ||
| return this.driver.sum(column); | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| async sumDistinct(column) { | ||
| return this.driver.sumDistinct(column); | ||
| } | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| async increment(column) { | ||
| await this.driver.increment(column); | ||
| } | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| async decrement(column) { | ||
| await this.driver.decrement(column); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async count(column = '*') { | ||
| return this.driver.count(column); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async countDistinct(column) { | ||
| return this.driver.countDistinct(column); | ||
| } | ||
| /** | ||
| * Find a value in database or throw exception if undefined. | ||
| */ | ||
| async findOrFail() { | ||
| return this.driver.findOrFail(); | ||
| } | ||
| /** | ||
| * Return a single data or, if no results are found, | ||
| * execute the given closure. | ||
| */ | ||
| async findOr(callback) { | ||
| return this.driver.findOr(callback); | ||
| } | ||
| /** | ||
| * Find value in database but returns only the value of | ||
| * selected column directly. | ||
| */ | ||
| async pluck(column) { | ||
| return this.driver.pluck(column); | ||
| } | ||
| /** | ||
| * Find many values in database but returns only the | ||
| * values of selected column directly. | ||
| */ | ||
| async pluckMany(column) { | ||
| return this.driver.pluckMany(column); | ||
| } | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| async find() { | ||
| return this.driver.find(); | ||
| } | ||
| /** | ||
| * Find a value in database and return as boolean. | ||
| */ | ||
| async exists() { | ||
| return this.driver.exists(); | ||
| } | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| async findMany() { | ||
| return this.driver.findMany(); | ||
| } | ||
| /** | ||
| * Find many values in database and return as a Collection. | ||
| */ | ||
| async collection() { | ||
| return this.driver.collection(); | ||
| } | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| async paginate(page = { page: 0, limit: 10, resourceUrl: '/' }, limit = 10, resourceUrl = '/') { | ||
| return this.driver.paginate(page, limit, resourceUrl); | ||
| } | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| async create(data) { | ||
| return this.driver.create(data); | ||
| } | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| async createMany(data) { | ||
| return this.driver.createMany(data); | ||
| } | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| async createOrUpdate(data) { | ||
| return this.driver.createOrUpdate(data); | ||
| } | ||
| /** | ||
| * Update data in database. | ||
| */ | ||
| async update(data) { | ||
| return this.driver.update(data); | ||
| } | ||
| /** | ||
| * Delete data in database. | ||
| */ | ||
| async delete() { | ||
| return this.driver.delete(); | ||
| } | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw(sql, bindings) { | ||
| return this.driver.raw(sql, bindings); | ||
| } | ||
| /** | ||
| * Set a new table to work with in query builder. | ||
| */ | ||
| table(tableName) { | ||
| this.driver.table(tableName); | ||
| return this; | ||
| } | ||
| /** | ||
| * Executes the given closure when the first argument is true. | ||
| */ | ||
| when(criteria, closure) { | ||
| if (criteria) { | ||
| closure(this, criteria); | ||
| return this; | ||
| } | ||
| return this; | ||
| } | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| dump() { | ||
| this.driver.dump(); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| select(...columns) { | ||
| this.driver.select(...columns); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| selectRaw(sql, bindings) { | ||
| this.driver.selectRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| from(table) { | ||
| this.driver.from(table); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| fromRaw(sql, bindings) { | ||
| this.driver.fromRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a join statement in your query. | ||
| */ | ||
| join(tableName, column1, operation, column2) { | ||
| this.driver.join(tableName, column1, operation, column2); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a left join statement in your query. | ||
| */ | ||
| leftJoin(tableName, column1, operation, column2) { | ||
| this.driver.leftJoin(tableName, column1, operation, column2); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a right join statement in your query. | ||
| */ | ||
| rightJoin(tableName, column1, operation, column2) { | ||
| this.driver.rightJoin(tableName, column1, operation, column2); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a cross join statement in your query. | ||
| */ | ||
| crossJoin(tableName, column1, operation, column2) { | ||
| this.driver.crossJoin(tableName, column1, operation, column2); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a full outer join statement in your query. | ||
| */ | ||
| fullOuterJoin(tableName, column1, operation, column2) { | ||
| this.driver.fullOuterJoin(tableName, column1, operation, column2); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a left outer join statement in your query. | ||
| */ | ||
| leftOuterJoin(tableName, column1, operation, column2) { | ||
| this.driver.leftOuterJoin(tableName, column1, operation, column2); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a right outer join statement in your query. | ||
| */ | ||
| rightOuterJoin(tableName, column1, operation, column2) { | ||
| this.driver.rightOuterJoin(tableName, column1, operation, column2); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| joinRaw(sql, bindings) { | ||
| this.driver.joinRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| groupBy(...columns) { | ||
| this.driver.groupBy(...columns); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| groupByRaw(sql, bindings) { | ||
| this.driver.groupByRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having statement in your query. | ||
| */ | ||
| having(column, operation, value) { | ||
| this.driver.having(column, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| havingRaw(sql, bindings) { | ||
| this.driver.havingRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| havingExists(closure) { | ||
| this.driver.havingExists(closure); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| havingNotExists(closure) { | ||
| this.driver.havingNotExists(closure); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| havingIn(column, values) { | ||
| this.driver.havingIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| havingNotIn(column, values) { | ||
| this.driver.havingNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| havingBetween(column, values) { | ||
| this.driver.havingBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| havingNotBetween(column, values) { | ||
| this.driver.havingNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| havingNull(column) { | ||
| this.driver.havingNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| havingNotNull(column) { | ||
| this.driver.havingNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having statement in your query. | ||
| */ | ||
| orHaving(column, operation, value) { | ||
| this.driver.orHaving(column, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| orHavingRaw(sql, bindings) { | ||
| this.driver.orHavingRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| orHavingExists(closure) { | ||
| this.driver.orHavingExists(closure); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| orHavingNotExists(closure) { | ||
| this.driver.orHavingNotExists(closure); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| orHavingIn(column, values) { | ||
| this.driver.orHavingIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| orHavingNotIn(column, values) { | ||
| this.driver.orHavingNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| orHavingBetween(column, values) { | ||
| this.driver.orHavingBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| orHavingNotBetween(column, values) { | ||
| this.driver.orHavingNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| orHavingNull(column) { | ||
| this.driver.orHavingNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| orHavingNotNull(column) { | ||
| this.driver.orHavingNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where statement in your query. | ||
| */ | ||
| where(statement, operation, value) { | ||
| this.driver.where(statement, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not statement in your query. | ||
| */ | ||
| whereNot(statement, value) { | ||
| this.driver.whereNot(statement, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| whereRaw(sql, bindings) { | ||
| this.driver.whereRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| whereExists(closure) { | ||
| this.driver.whereExists(closure); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| whereNotExists(closure) { | ||
| this.driver.whereNotExists(closure); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| whereLike(column, value) { | ||
| this.driver.whereLike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| whereILike(column, value) { | ||
| this.driver.whereILike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| whereIn(column, values) { | ||
| this.driver.whereIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| whereNotIn(column, values) { | ||
| this.driver.whereNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| whereBetween(column, values) { | ||
| this.driver.whereBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| whereNotBetween(column, values) { | ||
| this.driver.whereNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| whereNull(column) { | ||
| this.driver.whereNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| whereNotNull(column) { | ||
| this.driver.whereNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a or where statement in your query. | ||
| */ | ||
| orWhere(statement, operation, value) { | ||
| this.driver.orWhere(statement, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not statement in your query. | ||
| */ | ||
| orWhereNot(statement, value) { | ||
| this.driver.orWhereNot(statement, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| */ | ||
| orWhereRaw(sql, bindings) { | ||
| this.driver.orWhereRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| orWhereExists(closure) { | ||
| this.driver.orWhereExists(closure); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| orWhereNotExists(closure) { | ||
| this.driver.orWhereNotExists(closure); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where like statement in your query. | ||
| */ | ||
| orWhereLike(statement, value) { | ||
| this.driver.orWhereLike(statement, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where ILike statement in your query. | ||
| */ | ||
| orWhereILike(statement, value) { | ||
| this.driver.orWhereILike(statement, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| orWhereIn(column, values) { | ||
| this.driver.orWhereIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| orWhereNotIn(column, values) { | ||
| this.driver.orWhereNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| orWhereBetween(column, values) { | ||
| this.driver.orWhereBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| orWhereNotBetween(column, values) { | ||
| this.driver.orWhereNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| orWhereNull(column) { | ||
| this.driver.orWhereNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| orWhereNotNull(column) { | ||
| this.driver.orWhereNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| orderBy(column, direction = 'ASC') { | ||
| this.driver.orderBy(column, direction.toUpperCase()); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| orderByRaw(sql, bindings) { | ||
| this.driver.orderByRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| latest(column = 'createdAt') { | ||
| this.driver.latest(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| oldest(column = 'createdAt') { | ||
| this.driver.oldest(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| offset(number) { | ||
| this.driver.offset(number); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| limit(number) { | ||
| this.driver.limit(number); | ||
| return this; | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { Knex } from 'knex'; | ||
| import type { ConnectionOptions } from '#src/types'; | ||
| import type { FakeDriver } from '#src/database/drivers/FakeDriver'; | ||
| import { QueryBuilder } from '#src/database/builders/QueryBuilder'; | ||
| import { Macroable } from '@athenna/common'; | ||
| import type { MongoDriver } from '#src/database/drivers/MongoDriver'; | ||
| import type { MySqlDriver } from '#src/database/drivers/MySqlDriver'; | ||
| import type { SqliteDriver } from '#src/database/drivers/SqliteDriver'; | ||
| import type { Driver as DriverImpl } from '#src/database/drivers/Driver'; | ||
| import type { Transaction } from '#src/database/transactions/Transaction'; | ||
| import type { PostgresDriver } from '#src/database/drivers/PostgresDriver'; | ||
| export declare class DatabaseImpl<Driver extends DriverImpl = any> extends Macroable { | ||
| /** | ||
| * The connection name used for this instance. | ||
| */ | ||
| connectionName: string; | ||
| /** | ||
| * The drivers responsible for handling database operations. | ||
| */ | ||
| driver: Driver; | ||
| /** | ||
| * Creates a new instance of DatabaseImpl. | ||
| */ | ||
| constructor(athennaDbOpts?: ConnectionOptions); | ||
| connection(con: 'mongo', options?: ConnectionOptions): DatabaseImpl<MongoDriver>; | ||
| connection(con: 'mysql', options?: ConnectionOptions): DatabaseImpl<MySqlDriver>; | ||
| connection(con: 'sqlite', options?: ConnectionOptions): DatabaseImpl<SqliteDriver>; | ||
| connection(con: 'postgres', options?: ConnectionOptions): DatabaseImpl<PostgresDriver>; | ||
| connection(con: 'fake', options?: ConnectionOptions): DatabaseImpl<typeof FakeDriver>; | ||
| connection(con: 'mongo' | 'mysql' | 'sqlite' | 'postgres' | 'fake' | string, options?: ConnectionOptions): DatabaseImpl<MongoDriver> | DatabaseImpl<MySqlDriver> | DatabaseImpl<SqliteDriver> | DatabaseImpl<PostgresDriver> | DatabaseImpl<typeof FakeDriver>; | ||
| /** | ||
| * Verify if database is already connected. | ||
| */ | ||
| isConnected(): boolean; | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| connect(options?: ConnectionOptions): DatabaseImpl<Driver>; | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| close(): Promise<void>; | ||
| /** | ||
| * Close all the connections with all databases. | ||
| */ | ||
| closeAll(): Promise<void>; | ||
| /** | ||
| * Return the client of driver. | ||
| */ | ||
| getClient(): any; | ||
| /** | ||
| * Return the query builder of driver. | ||
| */ | ||
| getQueryBuilder(): any; | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| startTransaction(): Promise<Transaction<Driver>>; | ||
| /** | ||
| * Run database seeders. | ||
| */ | ||
| runSeeders(options?: { | ||
| task?: any; | ||
| path?: string; | ||
| classes?: string[]; | ||
| }): Promise<void>; | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| runMigrations(): Promise<void>; | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| revertMigrations(): Promise<void>; | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| getDatabases(): Promise<string[]>; | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| getCurrentDatabase(): Promise<string | undefined>; | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| hasDatabase(database: string): Promise<boolean>; | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| createDatabase(database: string): Promise<void>; | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| dropDatabase(database: string): Promise<void>; | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| getTables(): Promise<string[]>; | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| hasTable(table: string): Promise<boolean>; | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| createTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>; | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| alterTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>; | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| dropTable(table: string): Promise<void>; | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| truncate(table: string): Promise<void>; | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw<T = any>(sql: string, bindings?: any): Knex.Raw<T>; | ||
| /** | ||
| * Creates a new instance of QueryBuilder for this table. | ||
| */ | ||
| table<T = any>(table: string | any): QueryBuilder<T, Driver>; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { QueryBuilder } from '#src/database/builders/QueryBuilder'; | ||
| import { Path, Module, Options, Macroable } from '@athenna/common'; | ||
| import { ConnectionFactory } from '#src/factories/ConnectionFactory'; | ||
| export class DatabaseImpl extends Macroable { | ||
| /** | ||
| * Creates a new instance of DatabaseImpl. | ||
| */ | ||
| constructor(athennaDbOpts) { | ||
| super(); | ||
| /** | ||
| * The connection name used for this instance. | ||
| */ | ||
| this.connectionName = Config.get('database.default'); | ||
| /** | ||
| * The drivers responsible for handling database operations. | ||
| */ | ||
| this.driver = null; | ||
| this.driver = ConnectionFactory.fabricate(this.connectionName); | ||
| this.connect(athennaDbOpts); | ||
| } | ||
| /** | ||
| * Change the database connection. | ||
| */ | ||
| connection(con, options) { | ||
| const driver = ConnectionFactory.fabricate(con); | ||
| const database = new DatabaseImpl(options); | ||
| database.connectionName = con; | ||
| database.driver = driver; | ||
| return database.connect(options); | ||
| } | ||
| /** | ||
| * Verify if database is already connected. | ||
| */ | ||
| isConnected() { | ||
| return this.driver.isConnected; | ||
| } | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| connect(options) { | ||
| this.driver.connect(options); | ||
| return this; | ||
| } | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| async close() { | ||
| await this.driver.close(); | ||
| } | ||
| /** | ||
| * Close all the connections with all databases. | ||
| */ | ||
| async closeAll() { | ||
| const cons = ConnectionFactory.availableConnections(); | ||
| const promises = cons.map(con => { | ||
| const driver = ConnectionFactory.fabricate(con); | ||
| return driver.close().then(() => ConnectionFactory.setClient(con, null)); | ||
| }); | ||
| await Promise.all(promises); | ||
| } | ||
| /** | ||
| * Return the client of driver. | ||
| */ | ||
| getClient() { | ||
| return this.driver.getClient(); | ||
| } | ||
| /** | ||
| * Return the query builder of driver. | ||
| */ | ||
| getQueryBuilder() { | ||
| return this.driver.getQueryBuilder(); | ||
| } | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| async startTransaction() { | ||
| return this.driver.startTransaction(); | ||
| } | ||
| /** | ||
| * Run database seeders. | ||
| */ | ||
| async runSeeders(options = {}) { | ||
| options = Options.create(options, { | ||
| classes: [], | ||
| task: null, | ||
| path: Path.seeders() | ||
| }); | ||
| const seeds = await Module.getAllFrom(options.path); | ||
| for (const Seed of seeds) { | ||
| if (options.classes?.length && !options.classes.includes(Seed.name)) { | ||
| continue; | ||
| } | ||
| if (!options.task) { | ||
| await new Seed().run(this); | ||
| continue; | ||
| } | ||
| const msg = `Running "${Seed.name}" seeder`; | ||
| options.task.addPromise(msg, () => new Seed().run(this)); | ||
| } | ||
| } | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| async runMigrations() { | ||
| await this.driver.runMigrations(); | ||
| } | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| async revertMigrations() { | ||
| await this.driver.revertMigrations(); | ||
| } | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| async getDatabases() { | ||
| return this.driver.getDatabases(); | ||
| } | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| async getCurrentDatabase() { | ||
| return this.driver.getCurrentDatabase(); | ||
| } | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| async hasDatabase(database) { | ||
| return this.driver.hasDatabase(database); | ||
| } | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| async createDatabase(database) { | ||
| await this.driver.createDatabase(database); | ||
| } | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| async dropDatabase(database) { | ||
| await this.driver.dropDatabase(database); | ||
| } | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| async getTables() { | ||
| return this.driver.getTables(); | ||
| } | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| async hasTable(table) { | ||
| return this.driver.hasTable(table); | ||
| } | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| async createTable(table, closure) { | ||
| await this.driver.createTable(table, closure); | ||
| } | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| async alterTable(table, closure) { | ||
| await this.driver.alterTable(table, closure); | ||
| } | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| async dropTable(table) { | ||
| await this.driver.dropTable(table); | ||
| } | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| async truncate(table) { | ||
| return this.driver.truncate(table); | ||
| } | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw(sql, bindings) { | ||
| return this.driver.raw(sql, bindings); | ||
| } | ||
| /** | ||
| * Creates a new instance of QueryBuilder for this table. | ||
| */ | ||
| table(table) { | ||
| return new QueryBuilder(this.driver, table); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Collection, type PaginatedResponse, type PaginationOptions } from '@athenna/common'; | ||
| import type { Knex, TableBuilder } from 'knex'; | ||
| import type { ModelSchema } from '#src/models/schemas/ModelSchema'; | ||
| import type { Transaction } from '#src/database/transactions/Transaction'; | ||
| import type { Direction, ConnectionOptions, Operations } from '#src/types'; | ||
| export declare abstract class Driver<Client = any, QB = any> { | ||
| /** | ||
| * Set the primary key of the driver. | ||
| */ | ||
| primaryKey: string; | ||
| /** | ||
| * Set if this instance is connected with database. | ||
| */ | ||
| isConnected: boolean; | ||
| /** | ||
| * Set if the connection will be saved on factory. | ||
| */ | ||
| isSavedOnFactory: boolean; | ||
| /** | ||
| * The connection name used for this instance. | ||
| */ | ||
| connection: string; | ||
| /** | ||
| * Set the table that this instance will work with. | ||
| */ | ||
| tableName: string; | ||
| /** | ||
| * Set the client of this driver. | ||
| */ | ||
| client: Client; | ||
| /** | ||
| * The main query builder of driver. | ||
| */ | ||
| qb: QB; | ||
| /** | ||
| * Use set query builder instead of creating a new one | ||
| * using client. | ||
| */ | ||
| useSetQB: boolean; | ||
| /** | ||
| * Creates a new instance of the Driver. | ||
| */ | ||
| constructor(connection: string | any, client?: Client); | ||
| /** | ||
| * Import knex in a method to be easier to mock. | ||
| */ | ||
| getKnex(): any; | ||
| /** | ||
| * Import mongoose in a method to be easier to mock. | ||
| */ | ||
| getMongoose(): any; | ||
| /** | ||
| * Clone the driver instance. | ||
| */ | ||
| clone(): Driver<Client, QB>; | ||
| /** | ||
| * Return the client of driver. | ||
| */ | ||
| getClient(): Client; | ||
| /** | ||
| * Set a client in driver. | ||
| */ | ||
| setClient(client: Client): this; | ||
| /** | ||
| * Return the query builder of driver. | ||
| */ | ||
| getQueryBuilder(): QB; | ||
| /** | ||
| * Set a query builder in driver. | ||
| */ | ||
| setQueryBuilder(queryBuilder: QB, options?: { | ||
| useSetQB?: boolean; | ||
| }): this; | ||
| /** | ||
| * Set the primary key of the driver. | ||
| */ | ||
| setPrimaryKey(primaryKey: string): this; | ||
| /** | ||
| * Create a join clause by join type | ||
| */ | ||
| joinByType(joinType: string, table: any, column1?: string, operation?: string | Operations, column2?: string): this; | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| abstract connect(options?: ConnectionOptions): void; | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| abstract close(): Promise<void>; | ||
| /** | ||
| * Creates a new instance of query builder. | ||
| */ | ||
| abstract query(): QB; | ||
| /** | ||
| * Sync a model schema with the driver. | ||
| */ | ||
| abstract sync(schema: ModelSchema): Promise<any>; | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| abstract startTransaction(): Promise<Transaction<Client, QB>>; | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| abstract commitTransaction(): Promise<void>; | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| abstract rollbackTransaction(): Promise<void>; | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| abstract runMigrations(): Promise<void>; | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| abstract revertMigrations(): Promise<void>; | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| abstract getDatabases(): Promise<string[]>; | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| abstract getCurrentDatabase(): Promise<string | undefined>; | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| abstract hasDatabase(database: string): Promise<boolean>; | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| abstract createDatabase(database: string): Promise<void>; | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| abstract dropDatabase(database: string): Promise<void>; | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| abstract getTables(): Promise<string[]>; | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| abstract hasTable(table: string): Promise<boolean>; | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| abstract createTable(table: string, closure?: TableBuilder): Promise<void>; | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| abstract alterTable(table: string, closure?: TableBuilder): Promise<void>; | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| abstract dropTable(table: string): Promise<void>; | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| abstract truncate(table: string): Promise<void>; | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| abstract raw<T = any>(sql: string, bindings?: any): Knex.Raw<T>; | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| abstract avg(column: string): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| abstract avgDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| abstract max(column: string): Promise<string>; | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| abstract min(column: string): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| abstract sum(column: string): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column in distinct mode. | ||
| */ | ||
| abstract sumDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| abstract increment(column: string): Promise<void>; | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| abstract decrement(column: string): Promise<void>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| abstract count(column?: string): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| abstract countDistinct(column?: string): Promise<string>; | ||
| /** | ||
| * Find a value in database and return as boolean. | ||
| */ | ||
| exists(): Promise<boolean>; | ||
| /** | ||
| * Find a value in database or throw exception if undefined. | ||
| */ | ||
| findOrFail<T = any>(): Promise<T>; | ||
| /** | ||
| * Return a single model instance or, if no results are found, | ||
| * execute the given closure. | ||
| */ | ||
| findOr<T = any>(closure: () => T | Promise<T>): Promise<T>; | ||
| /** | ||
| * Find value in database but returns only the value of | ||
| * selected column directly. | ||
| */ | ||
| pluck<T = any, K extends keyof T = keyof T>(column: K): Promise<T[K]>; | ||
| /** | ||
| * Find many values in database but returns only the | ||
| * values of selected column directly. | ||
| */ | ||
| pluckMany<T = any, K extends keyof T = keyof T>(column: K): Promise<T[K][]>; | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| abstract find<T = any>(): Promise<T>; | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| abstract findMany<T = any>(): Promise<T[]>; | ||
| /** | ||
| * Find many values in database and return as a Collection. | ||
| */ | ||
| collection<T = any>(): Promise<Collection<T>>; | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| abstract paginate<T = any>(page?: PaginationOptions | number, limit?: number, resourceUrl?: string): Promise<PaginatedResponse<T>>; | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| abstract create<T = any>(data?: Partial<T>): Promise<T>; | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| abstract createMany<T = any>(data?: Partial<T>[]): Promise<T[]>; | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| abstract createOrUpdate<T = any>(data?: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| abstract update<T = any>(data: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Delete one value in database. | ||
| */ | ||
| abstract delete(): Promise<void>; | ||
| /** | ||
| * Set the table that this query will be executed. | ||
| */ | ||
| abstract table(tableName: string | any): this; | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| abstract dump(): this; | ||
| /** | ||
| * Executes the given closure when the first argument is true. | ||
| */ | ||
| when(criteria: any, closure: (query: this, criteriaValue?: any) => any | Promise<any>): this; | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| abstract select(...columns: string[]): this; | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| abstract selectRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| abstract from(table: string): this; | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| abstract fromRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a join statement in your query. | ||
| */ | ||
| abstract join(table: any, column1?: string, operation?: string | Operations, column2?: string): this; | ||
| /** | ||
| * Set a left join statement in your query. | ||
| */ | ||
| abstract leftJoin(table: any, column1?: string, operation?: string | Operations, column2?: string): this; | ||
| /** | ||
| * Set a right join statement in your query. | ||
| */ | ||
| abstract rightJoin(table: any, column1?: string, operation?: string | Operations, column2?: string): this; | ||
| /** | ||
| * Set a cross join statement in your query. | ||
| */ | ||
| abstract crossJoin(table: any, column1?: string, operation?: string | Operations, column2?: string): this; | ||
| /** | ||
| * Set a full outer join statement in your query. | ||
| */ | ||
| abstract fullOuterJoin(table: any, column1?: string, operation?: string | Operations, column2?: string): this; | ||
| /** | ||
| * Set a left outer join statement in your query. | ||
| */ | ||
| abstract leftOuterJoin(table: any, column1?: string, operation?: string | Operations, column2?: string): this; | ||
| /** | ||
| * Set a right outer join statement in your query. | ||
| */ | ||
| abstract rightOuterJoin(table: any, column1?: string, operation?: string | Operations, column2?: string): this; | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| abstract joinRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| abstract groupBy(...columns: string[]): this; | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| abstract groupByRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a having statement in your query. | ||
| */ | ||
| abstract having(column: any, operation?: string | Operations, value?: any): this; | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| abstract havingRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| abstract havingExists(closure: (query: Driver<Client, QB>) => void): this; | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| abstract havingNotExists(closure: (query: Driver<Client, QB>) => void): this; | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| abstract havingIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| abstract havingNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| abstract havingBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| abstract havingNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| abstract havingNull(column: string): this; | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| abstract havingNotNull(column: string): this; | ||
| /** | ||
| * Set an or having statement in your query. | ||
| */ | ||
| abstract orHaving(column: any, operation?: string | Operations, value?: any): this; | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| abstract orHavingRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| abstract orHavingExists(closure: (query: Driver<Client, QB>) => void): this; | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| abstract orHavingNotExists(closure: (query: Driver<Client, QB>) => void): this; | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| abstract orHavingIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| abstract orHavingNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| abstract orHavingBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| abstract orHavingNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| abstract orHavingNull(column: string): this; | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| abstract orHavingNotNull(column: string): this; | ||
| /** | ||
| * Set a where statement in your query. | ||
| */ | ||
| abstract where(statement: any, operation?: string | Operations, value?: any): this; | ||
| /** | ||
| * Set a where not statement in your query. | ||
| */ | ||
| abstract whereNot(statement: any, value?: any): this; | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| abstract whereRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| abstract whereExists(closure: (query: Driver<Client, QB>) => void): this; | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| abstract whereNotExists(closure: (query: Driver<Client, QB>) => void): this; | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| abstract whereLike(statement: any, value?: any): this; | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| abstract whereILike(statement: any, value?: any): this; | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| abstract whereIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| abstract whereNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| abstract whereBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| abstract whereNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| abstract whereNull(column: string): this; | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| abstract whereNotNull(column: string): this; | ||
| /** | ||
| * Set a or where statement in your query. | ||
| */ | ||
| abstract orWhere(statement: string | Record<string, any>, operation: string | Record<string, any>, value: Record<string, any>): this; | ||
| /** | ||
| * Set an or where not statement in your query. | ||
| */ | ||
| abstract orWhereNot(statement: string | Record<string, any>, value: any): this; | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| * | ||
| * @param sql {string} | ||
| * @param [bindings] {any} | ||
| * @return {MySqlDriver} | ||
| */ | ||
| abstract orWhereRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| abstract orWhereExists(closure: (query: Driver<Client, QB>) => void): this; | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| abstract orWhereNotExists(closure: (query: Driver<Client, QB>) => void): this; | ||
| /** | ||
| * Set an or where like statement in your query. | ||
| */ | ||
| abstract orWhereLike(statement: any, value?: any): this; | ||
| /** | ||
| * Set an or where ILike statement in your query. | ||
| */ | ||
| abstract orWhereILike(statement: any, value?: any): this; | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| abstract orWhereIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| abstract orWhereNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| abstract orWhereBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| abstract orWhereNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| abstract orWhereNull(column: string): this; | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| abstract orWhereNotNull(column: string): this; | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| abstract orderBy(column: string, direction?: Direction): this; | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| abstract orderByRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| abstract latest(column?: string): this; | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| abstract oldest(column?: string): this; | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| abstract offset(number: number): this; | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| abstract limit(number: number): this; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Module, Options, Collection } from '@athenna/common'; | ||
| import { NotFoundDataException } from '#src/exceptions/NotFoundDataException'; | ||
| export class Driver { | ||
| /** | ||
| * Creates a new instance of the Driver. | ||
| */ | ||
| constructor(connection, client = null) { | ||
| /** | ||
| * Set the primary key of the driver. | ||
| */ | ||
| this.primaryKey = 'id'; | ||
| /** | ||
| * Set if this instance is connected with database. | ||
| */ | ||
| this.isConnected = false; | ||
| /** | ||
| * Set if the connection will be saved on factory. | ||
| */ | ||
| this.isSavedOnFactory = false; | ||
| /** | ||
| * The connection name used for this instance. | ||
| */ | ||
| this.connection = null; | ||
| /** | ||
| * Set the table that this instance will work with. | ||
| */ | ||
| this.tableName = null; | ||
| /** | ||
| * Set the client of this driver. | ||
| */ | ||
| this.client = null; | ||
| /** | ||
| * The main query builder of driver. | ||
| */ | ||
| this.qb = null; | ||
| /** | ||
| * Use set query builder instead of creating a new one | ||
| * using client. | ||
| */ | ||
| this.useSetQB = false; | ||
| this.connection = connection; | ||
| if (client) { | ||
| this.client = client; | ||
| this.isConnected = true; | ||
| this.isSavedOnFactory = true; | ||
| } | ||
| } | ||
| /** | ||
| * Import knex in a method to be easier to mock. | ||
| */ | ||
| getKnex() { | ||
| const require = Module.createRequire(import.meta.url); | ||
| return require('knex'); | ||
| } | ||
| /** | ||
| * Import mongoose in a method to be easier to mock. | ||
| */ | ||
| getMongoose() { | ||
| const require = Module.createRequire(import.meta.url); | ||
| let mongoose = require('mongoose'); | ||
| if (!mongoose.createConnection) { | ||
| mongoose = mongoose.default; | ||
| } | ||
| return mongoose; | ||
| } | ||
| /** | ||
| * Clone the driver instance. | ||
| */ | ||
| clone() { | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| return new this.constructor(this.connection, this.client); | ||
| } | ||
| /** | ||
| * Return the client of driver. | ||
| */ | ||
| getClient() { | ||
| return this.client; | ||
| } | ||
| /** | ||
| * Set a client in driver. | ||
| */ | ||
| setClient(client) { | ||
| this.client = client; | ||
| return this; | ||
| } | ||
| /** | ||
| * Return the query builder of driver. | ||
| */ | ||
| getQueryBuilder() { | ||
| return this.qb; | ||
| } | ||
| /** | ||
| * Set a query builder in driver. | ||
| */ | ||
| setQueryBuilder(queryBuilder, options = {}) { | ||
| options = Options.create(options, { | ||
| useSetQB: false | ||
| }); | ||
| this.qb = queryBuilder; | ||
| this.useSetQB = !this.qb ? false : options.useSetQB; | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the primary key of the driver. | ||
| */ | ||
| setPrimaryKey(primaryKey) { | ||
| this.primaryKey = primaryKey; | ||
| return this; | ||
| } | ||
| /** | ||
| * Create a join clause by join type | ||
| */ | ||
| joinByType(joinType, table, column1, operation, column2) { | ||
| if (!column1) { | ||
| this.qb[joinType](table); | ||
| return this; | ||
| } | ||
| if (!operation) { | ||
| this.qb[joinType](table, column1); | ||
| return this; | ||
| } | ||
| if (!column2) { | ||
| this.qb[joinType](table, column1, operation); | ||
| return this; | ||
| } | ||
| this.qb[joinType](table, column1, operation, column2); | ||
| return this; | ||
| } | ||
| /** | ||
| * Find a value in database and return as boolean. | ||
| */ | ||
| async exists() { | ||
| const data = await this.find(); | ||
| return !!data; | ||
| } | ||
| /** | ||
| * Find a value in database or throw exception if undefined. | ||
| */ | ||
| async findOrFail() { | ||
| const data = await this.find(); | ||
| if (!data) { | ||
| throw new NotFoundDataException(this.connection); | ||
| } | ||
| return data; | ||
| } | ||
| /** | ||
| * Return a single model instance or, if no results are found, | ||
| * execute the given closure. | ||
| */ | ||
| async findOr(closure) { | ||
| const data = await this.find(); | ||
| if (!data) { | ||
| return closure(); | ||
| } | ||
| return data; | ||
| } | ||
| /** | ||
| * Find value in database but returns only the value of | ||
| * selected column directly. | ||
| */ | ||
| async pluck(column) { | ||
| const data = await this.find(); | ||
| return data[column]; | ||
| } | ||
| /** | ||
| * Find many values in database but returns only the | ||
| * values of selected column directly. | ||
| */ | ||
| async pluckMany(column) { | ||
| const data = await this.findMany(); | ||
| return data.map(d => d[column]); | ||
| } | ||
| /** | ||
| * Find many values in database and return as a Collection. | ||
| */ | ||
| async collection() { | ||
| return new Collection(await this.findMany()); | ||
| } | ||
| /** | ||
| * Executes the given closure when the first argument is true. | ||
| */ | ||
| when(criteria, closure) { | ||
| if (!criteria) { | ||
| return this; | ||
| } | ||
| closure(this, criteria); | ||
| return this; | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Collection, type PaginatedResponse } from '@athenna/common'; | ||
| import type { ConnectionOptions, Operations } from '#src/types'; | ||
| import { Transaction } from '#src/database/transactions/Transaction'; | ||
| export declare class FakeDriver { | ||
| constructor(connection?: string, client?: any); | ||
| static primaryKey: string; | ||
| static tables: string[]; | ||
| static databases: string[]; | ||
| static isConnected: boolean; | ||
| static isSavedOnFactory: boolean; | ||
| static tableName: string; | ||
| static connection: string; | ||
| static client: any; | ||
| static qb: any; | ||
| static useSetQB: boolean; | ||
| static joinByType(): typeof FakeDriver; | ||
| static getKnex(): void; | ||
| static getMongoose(): void; | ||
| static clone(): typeof FakeDriver; | ||
| static setPrimaryKey(primaryKey: string): typeof FakeDriver; | ||
| static getClient(): any; | ||
| static setClient(client: any): typeof FakeDriver; | ||
| static getQueryBuilder(): any; | ||
| static setQueryBuilder(client: any): typeof FakeDriver; | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| static connect(options?: ConnectionOptions): void; | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| static close(): Promise<void>; | ||
| /** | ||
| * Creates a new instance of query builder. | ||
| */ | ||
| static query(): {}; | ||
| /** | ||
| * Sync a model schema with database. | ||
| */ | ||
| static sync(): Promise<void>; | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| static startTransaction(): Promise<Transaction>; | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| static commitTransaction(): Promise<void>; | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| static rollbackTransaction(): Promise<void>; | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| static runMigrations(): Promise<void>; | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| static revertMigrations(): Promise<void>; | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| static getDatabases(): Promise<string[]>; | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| static getCurrentDatabase(): Promise<string | undefined>; | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| static hasDatabase(database: string): Promise<boolean>; | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| static createDatabase(database: string): Promise<void>; | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| static dropDatabase(database: string): Promise<void>; | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| static getTables(): Promise<string[]>; | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| static hasTable(table: string): Promise<boolean>; | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| static createTable(table: string): Promise<void>; | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| static alterTable(): Promise<void>; | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| static dropTable(table: string): Promise<void>; | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| static truncate(table: string): Promise<void>; | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| static raw(): any; | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| static avg(): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| static avgDistinct(): Promise<string>; | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| static max(): Promise<string>; | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| static min(): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| static sum(): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column in distinct mode. | ||
| */ | ||
| static sumDistinct(): Promise<string>; | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| static increment(): Promise<void>; | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| static decrement(): Promise<void>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| static count(): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| static countDistinct(): Promise<string>; | ||
| /** | ||
| * Find value in database but returns only the value of | ||
| * selected column directly. | ||
| */ | ||
| static pluck(): Promise<any>; | ||
| /** | ||
| * Find many values in database but returns only the | ||
| * values of selected column directly. | ||
| */ | ||
| static pluckMany(): Promise<any>; | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| static find(): Promise<any>; | ||
| /** | ||
| * Find a value in database and return as boolean. | ||
| */ | ||
| static exists(): Promise<boolean>; | ||
| /** | ||
| * Find a value in database or fail. | ||
| */ | ||
| static findOrFail(): Promise<any>; | ||
| /** | ||
| * Find a value in database or execute closure. | ||
| */ | ||
| static findOr(): Promise<any>; | ||
| /** | ||
| * Executes the given closure when the first argument is true. | ||
| */ | ||
| static when(criteria: any, closure: (query: typeof FakeDriver, criteriaValue?: any) => void): typeof FakeDriver; | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| static findMany(): Promise<any[]>; | ||
| /** | ||
| * Find many values in database and return as a Collection. | ||
| */ | ||
| static collection(): Promise<Collection<any>>; | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| static paginate<T = any>(page?: { | ||
| page: number; | ||
| limit: number; | ||
| resourceUrl: string; | ||
| }, limit?: number, resourceUrl?: string): Promise<PaginatedResponse<T>>; | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| static create<T = any>(data?: Partial<T>): Promise<T>; | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| static createMany<T = any>(data?: Partial<T>[]): Promise<T[]>; | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| static createOrUpdate<T = any>(data?: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| static update<T = any>(data: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Delete one value in database. | ||
| */ | ||
| static delete(): Promise<void>; | ||
| /** | ||
| * Set the table that this query will be executed. | ||
| */ | ||
| static table(table: string): typeof FakeDriver; | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| static dump(): typeof FakeDriver; | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| static select(...columns: string[]): typeof FakeDriver; | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| static selectRaw(): typeof FakeDriver; | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| static from(): typeof FakeDriver; | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| static fromRaw(): typeof FakeDriver; | ||
| /** | ||
| * Set a join statement in your query. | ||
| */ | ||
| static join(): typeof FakeDriver; | ||
| /** | ||
| * Set a left join statement in your query. | ||
| */ | ||
| static leftJoin(): typeof FakeDriver; | ||
| /** | ||
| * Set a right join statement in your query. | ||
| */ | ||
| static rightJoin(): typeof FakeDriver; | ||
| /** | ||
| * Set a cross join statement in your query. | ||
| */ | ||
| static crossJoin(): typeof FakeDriver; | ||
| /** | ||
| * Set a full outer join statement in your query. | ||
| */ | ||
| static fullOuterJoin(): typeof FakeDriver; | ||
| /** | ||
| * Set a left outer join statement in your query. | ||
| */ | ||
| static leftOuterJoin(): typeof FakeDriver; | ||
| /** | ||
| * Set a right outer join statement in your query. | ||
| */ | ||
| static rightOuterJoin(): typeof FakeDriver; | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| static joinRaw(): typeof FakeDriver; | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| static groupBy(): typeof FakeDriver; | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| static groupByRaw(): typeof FakeDriver; | ||
| static having(column: string): typeof FakeDriver; | ||
| static having(column: string, value: any): typeof FakeDriver; | ||
| static having(column: string, operation: Operations, value: any): typeof FakeDriver; | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| static havingRaw(): typeof FakeDriver; | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| static havingExists(): typeof FakeDriver; | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| static havingNotExists(): typeof FakeDriver; | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| static havingIn(): typeof FakeDriver; | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| static havingNotIn(): typeof FakeDriver; | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| static havingBetween(): typeof FakeDriver; | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| static havingNotBetween(): typeof FakeDriver; | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| static havingNull(): typeof FakeDriver; | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| static havingNotNull(): typeof FakeDriver; | ||
| static orHaving(column: string): typeof FakeDriver; | ||
| static orHaving(column: string, value: any): typeof FakeDriver; | ||
| static orHaving(column: string, operation: Operations, value: any): typeof FakeDriver; | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| static orHavingRaw(): typeof FakeDriver; | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| static orHavingExists(): typeof FakeDriver; | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| static orHavingNotExists(): typeof FakeDriver; | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| static orHavingIn(): typeof FakeDriver; | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| static orHavingNotIn(): typeof FakeDriver; | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| static orHavingBetween(): typeof FakeDriver; | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| static orHavingNotBetween(): typeof FakeDriver; | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| static orHavingNull(): typeof FakeDriver; | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| static orHavingNotNull(): typeof FakeDriver; | ||
| static where(statement: Record<string, any>): typeof FakeDriver; | ||
| static where(key: string, value: any): typeof FakeDriver; | ||
| static where(key: string, operation: Operations, value: any): typeof FakeDriver; | ||
| static whereNot(statement: Record<string, any>): any; | ||
| static whereNot(key: string, value: any): any; | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| static whereRaw(): typeof FakeDriver; | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| static whereExists(): typeof FakeDriver; | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| static whereNotExists(): typeof FakeDriver; | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| static whereLike(): typeof FakeDriver; | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| static whereILike(): typeof FakeDriver; | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| static whereIn(): typeof FakeDriver; | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| static whereNotIn(): typeof FakeDriver; | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| static whereBetween(): typeof FakeDriver; | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| static whereNotBetween(): typeof FakeDriver; | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| static whereNull(): typeof FakeDriver; | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| static whereNotNull(): typeof FakeDriver; | ||
| static orWhere(statement: Record<string, any>): typeof FakeDriver; | ||
| static orWhere(key: string, value: any): typeof FakeDriver; | ||
| static orWhere(key: string, operation: Operations, value: any): typeof FakeDriver; | ||
| static orWhereNot(statement: Record<string, any>): typeof FakeDriver; | ||
| static orWhereNot(key: string, value: any): typeof FakeDriver; | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| */ | ||
| static orWhereRaw(): typeof FakeDriver; | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| static orWhereExists(): typeof FakeDriver; | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| static orWhereNotExists(): typeof FakeDriver; | ||
| /** | ||
| * Set an or where like statement in your query. | ||
| */ | ||
| static orWhereLike(): typeof FakeDriver; | ||
| /** | ||
| * Set an or where ILike statement in your query. | ||
| */ | ||
| static orWhereILike(): typeof FakeDriver; | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| static orWhereIn(): typeof FakeDriver; | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| static orWhereNotIn(): typeof FakeDriver; | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| static orWhereBetween(): typeof FakeDriver; | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| static orWhereNotBetween(): typeof FakeDriver; | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| static orWhereNull(): typeof FakeDriver; | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| static orWhereNotNull(): typeof FakeDriver; | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| static orderBy(): typeof FakeDriver; | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| static orderByRaw(): typeof FakeDriver; | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| static latest(): typeof FakeDriver; | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| static oldest(): typeof FakeDriver; | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| static offset(): typeof FakeDriver; | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| static limit(): typeof FakeDriver; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Collection, Exec, Is, Json, Options } from '@athenna/common'; | ||
| import { Transaction } from '#src/database/transactions/Transaction'; | ||
| import { WrongMethodException } from '#src/exceptions/WrongMethodException'; | ||
| import { NotFoundDataException } from '#src/exceptions/NotFoundDataException'; | ||
| import { NotConnectedDatabaseException } from '#src/exceptions/NotConnectedDatabaseException'; | ||
| export class FakeDriver { | ||
| constructor(connection, client) { | ||
| FakeDriver.connection = connection; | ||
| if (client) { | ||
| FakeDriver.client = client; | ||
| FakeDriver.isConnected = true; | ||
| FakeDriver.isSavedOnFactory = true; | ||
| } | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| return FakeDriver; | ||
| } | ||
| static { this.primaryKey = 'id'; } | ||
| static { this.tables = ['fake']; } | ||
| static { this.databases = ['fake']; } | ||
| static { this.isConnected = false; } | ||
| static { this.isSavedOnFactory = false; } | ||
| static { this.tableName = 'fake'; } | ||
| static { this.connection = 'fake'; } | ||
| static { this.client = null; } | ||
| static { this.qb = null; } | ||
| static { this.useSetQB = false; } | ||
| static joinByType() { | ||
| return this; | ||
| } | ||
| static getKnex() { } | ||
| static getMongoose() { } | ||
| static clone() { | ||
| return Json.copy(FakeDriver); | ||
| } | ||
| static setPrimaryKey(primaryKey) { | ||
| this.primaryKey = primaryKey; | ||
| return this; | ||
| } | ||
| static getClient() { | ||
| return this.client; | ||
| } | ||
| static setClient(client) { | ||
| this.client = client; | ||
| return this; | ||
| } | ||
| static getQueryBuilder() { | ||
| return this.client; | ||
| } | ||
| static setQueryBuilder(client) { | ||
| this.client = client; | ||
| return this; | ||
| } | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| static connect(options = {}) { | ||
| options = Options.create(options, { | ||
| force: false, | ||
| saveOnFactory: true, | ||
| connect: true | ||
| }); | ||
| if (!options.connect) { | ||
| return; | ||
| } | ||
| if (this.isConnected && !options.force) { | ||
| return; | ||
| } | ||
| this.isConnected = true; | ||
| this.isSavedOnFactory = options.saveOnFactory; | ||
| } | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| static async close() { | ||
| if (!this.isConnected) { | ||
| return; | ||
| } | ||
| this.tableName = null; | ||
| this.isConnected = false; | ||
| } | ||
| /** | ||
| * Creates a new instance of query builder. | ||
| */ | ||
| static query() { | ||
| if (!this.isConnected) { | ||
| throw new NotConnectedDatabaseException(); | ||
| } | ||
| return {}; | ||
| } | ||
| /** | ||
| * Sync a model schema with database. | ||
| */ | ||
| static async sync() { } | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| static async startTransaction() { | ||
| return new Transaction(FakeDriver); | ||
| } | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| static async commitTransaction() { | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.isConnected = false; | ||
| } | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| static async rollbackTransaction() { | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.isConnected = false; | ||
| } | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| static async runMigrations() { } | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| static async revertMigrations() { } | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| static async getDatabases() { | ||
| return this.databases; | ||
| } | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| static async getCurrentDatabase() { | ||
| return this.databases[0]; | ||
| } | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| static async hasDatabase(database) { | ||
| const databases = await this.getDatabases(); | ||
| return databases.includes(database); | ||
| } | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| static async createDatabase(database) { | ||
| this.databases.push(database); | ||
| } | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| static async dropDatabase(database) { | ||
| const index = this.databases.indexOf(database); | ||
| this.databases.splice(index, 1); | ||
| } | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| static async getTables() { | ||
| return this.tables; | ||
| } | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| static async hasTable(table) { | ||
| const tables = await this.getTables(); | ||
| return tables.includes(table); | ||
| } | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| static async createTable(table) { | ||
| this.tables.push(table); | ||
| } | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| static async alterTable() { } | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| static async dropTable(table) { | ||
| const index = this.tables.indexOf(table); | ||
| this.tables.splice(index, 1); | ||
| } | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| static async truncate(table) { | ||
| this.tables.indexOf(table); | ||
| } | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| static raw() { | ||
| return {}; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| static async avg() { | ||
| return '1'; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| static async avgDistinct() { | ||
| return '1'; | ||
| } | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| static async max() { | ||
| return '1'; | ||
| } | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| static async min() { | ||
| return '1'; | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| static async sum() { | ||
| return '1'; | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column in distinct mode. | ||
| */ | ||
| static async sumDistinct() { | ||
| return '1'; | ||
| } | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| static async increment() { } | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| static async decrement() { } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| static async count() { | ||
| return '1'; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| static async countDistinct() { | ||
| return '1'; | ||
| } | ||
| /** | ||
| * Find value in database but returns only the value of | ||
| * selected column directly. | ||
| */ | ||
| static async pluck() { | ||
| return ''; | ||
| } | ||
| /** | ||
| * Find many values in database but returns only the | ||
| * values of selected column directly. | ||
| */ | ||
| static async pluckMany() { | ||
| return ['']; | ||
| } | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| static async find() { | ||
| return {}; | ||
| } | ||
| /** | ||
| * Find a value in database and return as boolean. | ||
| */ | ||
| static async exists() { | ||
| const data = await this.find(); | ||
| return !!data; | ||
| } | ||
| /** | ||
| * Find a value in database or fail. | ||
| */ | ||
| static async findOrFail() { | ||
| const data = await this.find(); | ||
| if (!data) { | ||
| throw new NotFoundDataException(this.connection); | ||
| } | ||
| return data; | ||
| } | ||
| /** | ||
| * Find a value in database or execute closure. | ||
| */ | ||
| static async findOr() { | ||
| return {}; | ||
| } | ||
| /** | ||
| * Executes the given closure when the first argument is true. | ||
| */ | ||
| static when(criteria, closure) { | ||
| if (!criteria) { | ||
| return this; | ||
| } | ||
| closure(this, criteria); | ||
| return this; | ||
| } | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| static async findMany() { | ||
| return [{}]; | ||
| } | ||
| /** | ||
| * Find many values in database and return as a Collection. | ||
| */ | ||
| static async collection() { | ||
| return new Collection(await this.findMany()); | ||
| } | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| static async paginate(page = { page: 0, limit: 10, resourceUrl: '/' }, limit = 10, resourceUrl = '/') { | ||
| if (Is.Number(page)) { | ||
| page = { page, limit, resourceUrl }; | ||
| } | ||
| const data = await this.findMany(); | ||
| return Exec.pagination(data, data.length, page); | ||
| } | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| static async create(data = {}) { | ||
| if (Is.Array(data)) { | ||
| throw new WrongMethodException('create', 'createMany'); | ||
| } | ||
| const created = await this.createMany([data]); | ||
| return created[0]; | ||
| } | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| static async createMany(data = []) { | ||
| if (!Is.Array(data)) { | ||
| throw new WrongMethodException('createMany', 'create'); | ||
| } | ||
| return data; | ||
| } | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| static async createOrUpdate(data = {}) { | ||
| return data; | ||
| } | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| static async update(data) { | ||
| return data; | ||
| } | ||
| /** | ||
| * Delete one value in database. | ||
| */ | ||
| static async delete() { } | ||
| /** | ||
| * Set the table that this query will be executed. | ||
| */ | ||
| static table(table) { | ||
| if (!this.isConnected) { | ||
| throw new NotConnectedDatabaseException(); | ||
| } | ||
| this.tableName = table; | ||
| return this; | ||
| } | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| static dump() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| static select(...columns) { | ||
| if (columns.includes('*')) { | ||
| return this; | ||
| } | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| static selectRaw() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| static from() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| static fromRaw() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a join statement in your query. | ||
| */ | ||
| static join() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a left join statement in your query. | ||
| */ | ||
| static leftJoin() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a right join statement in your query. | ||
| */ | ||
| static rightJoin() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a cross join statement in your query. | ||
| */ | ||
| static crossJoin() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a full outer join statement in your query. | ||
| */ | ||
| static fullOuterJoin() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a left outer join statement in your query. | ||
| */ | ||
| static leftOuterJoin() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a right outer join statement in your query. | ||
| */ | ||
| static rightOuterJoin() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| static joinRaw() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| static groupBy() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| static groupByRaw() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having statement in your query. | ||
| */ | ||
| static having() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| static havingRaw() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| static havingExists() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| static havingNotExists() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| static havingIn() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| static havingNotIn() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| static havingBetween() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| static havingNotBetween() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| static havingNull() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| static havingNotNull() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having statement in your query. | ||
| */ | ||
| static orHaving() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| static orHavingRaw() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| static orHavingExists() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| static orHavingNotExists() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| static orHavingIn() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| static orHavingNotIn() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| static orHavingBetween() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| static orHavingNotBetween() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| static orHavingNull() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| static orHavingNotNull() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where statement in your query. | ||
| */ | ||
| static where() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not statement in your query. | ||
| */ | ||
| static whereNot() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| static whereRaw() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| static whereExists() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| static whereNotExists() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| static whereLike() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| static whereILike() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| static whereIn() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| static whereNotIn() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| static whereBetween() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| static whereNotBetween() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| static whereNull() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| static whereNotNull() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a or where statement in your query. | ||
| */ | ||
| static orWhere() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not statement in your query. | ||
| */ | ||
| static orWhereNot() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| */ | ||
| static orWhereRaw() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| static orWhereExists() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| static orWhereNotExists() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where like statement in your query. | ||
| */ | ||
| static orWhereLike() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where ILike statement in your query. | ||
| */ | ||
| static orWhereILike() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| static orWhereIn() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| static orWhereNotIn() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| static orWhereBetween() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| static orWhereNotBetween() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| static orWhereNull() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| static orWhereNotNull() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| static orderBy() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| static orderByRaw() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| static latest() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| static oldest() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| static offset() { | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| static limit() { | ||
| return this; | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { type PaginatedResponse, type PaginationOptions } from '@athenna/common'; | ||
| import { Driver } from '#src/database/drivers/Driver'; | ||
| import { ModelSchema } from '#src/models/schemas/ModelSchema'; | ||
| import { Transaction } from '#src/database/transactions/Transaction'; | ||
| import type { Connection, Collection, ClientSession } from 'mongoose'; | ||
| import type { ConnectionOptions, Direction, Operations } from '#src/types'; | ||
| export declare class MongoDriver extends Driver<Connection, Collection> { | ||
| primaryKey: string; | ||
| session: ClientSession; | ||
| /** | ||
| * The where clause used in update queries. | ||
| */ | ||
| private _where; | ||
| /** | ||
| * The or where clause used in update queries. | ||
| */ | ||
| private _orWhere; | ||
| /** | ||
| * The aggregate pipeline to make mongo queries. | ||
| */ | ||
| private pipeline; | ||
| /** | ||
| * Set the mongo session that should be used by the driver. | ||
| */ | ||
| setSession(session: ClientSession): this; | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| connect(options?: ConnectionOptions): void; | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| close(): Promise<void>; | ||
| /** | ||
| * Creates a new instance of query builder. | ||
| */ | ||
| query(): Collection; | ||
| /** | ||
| * Sync a model schema with database. | ||
| */ | ||
| sync(schema: ModelSchema): Promise<void>; | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| startTransaction(): Promise<Transaction<Connection, Collection>>; | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| commitTransaction(): Promise<void>; | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| rollbackTransaction(): Promise<void>; | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| runMigrations(): Promise<void>; | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| revertMigrations(): Promise<void>; | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| getDatabases(): Promise<string[]>; | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| getCurrentDatabase(): Promise<string | undefined>; | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| hasDatabase(database: string): Promise<boolean>; | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| createDatabase(): Promise<void>; | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| dropDatabase(database: string): Promise<void>; | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| getTables(): Promise<string[]>; | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| hasTable(table: string): Promise<boolean>; | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| createTable(): Promise<void>; | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| alterTable(): Promise<void>; | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| dropTable(table: string): Promise<void>; | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| truncate(table: string): Promise<void>; | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw<T = any>(): T; | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| avg(column: string): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| avgDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| max(column: string): Promise<string>; | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| min(column: string): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| sum(column: string): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column in distinct mode. | ||
| */ | ||
| sumDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| increment(column: string): Promise<void>; | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| decrement(column: string): Promise<void>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| count(column?: string): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| countDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| find<T = any>(): Promise<T>; | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| findMany<T = any>(): Promise<T[]>; | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| paginate<T = any>(page?: PaginationOptions | number, limit?: number, resourceUrl?: string): Promise<PaginatedResponse<T>>; | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| create<T = any>(data?: Partial<T>): Promise<T>; | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| createMany<T = any>(data?: Partial<T>[]): Promise<T[]>; | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| createOrUpdate<T = any>(data?: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| update<T = any>(data: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Delete one value in database. | ||
| */ | ||
| delete(): Promise<void>; | ||
| /** | ||
| * Set the table that this query will be executed. | ||
| */ | ||
| table(table: string): this; | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| dump(): this; | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| select(...columns: string[]): this; | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| selectRaw(): this; | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| from(): this; | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| fromRaw(): this; | ||
| /** | ||
| * Set a join statement in your query. | ||
| */ | ||
| join(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a left join statement in your query. | ||
| */ | ||
| leftJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a right join statement in your query. | ||
| */ | ||
| rightJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a cross join statement in your query. | ||
| */ | ||
| crossJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a full outer join statement in your query. | ||
| */ | ||
| fullOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a left outer join statement in your query. | ||
| */ | ||
| leftOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a right outer join statement in your query. | ||
| */ | ||
| rightOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| joinRaw(): this; | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| groupBy(...columns: string[]): this; | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| groupByRaw(): this; | ||
| having(column: string): this; | ||
| having(column: string, value: any): this; | ||
| having(column: string, operation: Operations, value: any): this; | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| havingRaw(): this; | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| havingExists(): this; | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| havingNotExists(): this; | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| havingIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| havingNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| havingBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| havingNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| havingNull(column: string): this; | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| havingNotNull(column: string): this; | ||
| orHaving(column: string): this; | ||
| orHaving(column: string, value: any): this; | ||
| orHaving(column: string, operation: Operations, value: any): this; | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| orHavingRaw(): this; | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| orHavingExists(): this; | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| orHavingNotExists(): this; | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| orHavingIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| orHavingNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| orHavingBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| orHavingNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| orHavingNull(column: string): this; | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| orHavingNotNull(column: string): this; | ||
| where(statement: Record<string, any>): this; | ||
| where(key: string, value: any): this; | ||
| where(key: string, operation: Operations, value: any): this; | ||
| whereNot(statement: Record<string, any>): this; | ||
| whereNot(key: string, value: any): this; | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| whereRaw(): this; | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| whereExists(): this; | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| whereNotExists(): this; | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| whereLike(column: string, value: any): this; | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| whereILike(column: string, value: any): this; | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| whereIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| whereNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| whereBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| whereNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| whereNull(column: string): this; | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| whereNotNull(column: string): this; | ||
| orWhere(statement: Record<string, any>): this; | ||
| orWhere(key: string, value: any): this; | ||
| orWhere(key: string, operation: Operations, value: any): this; | ||
| orWhereNot(statement: Record<string, any>): this; | ||
| orWhereNot(key: string, value: any): this; | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| */ | ||
| orWhereRaw(): this; | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| orWhereExists(): this; | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| orWhereNotExists(): this; | ||
| /** | ||
| * Set an or where like statement in your query. | ||
| */ | ||
| orWhereLike(column: string, value: any): this; | ||
| /** | ||
| * Set an or where ILike statement in your query. | ||
| */ | ||
| orWhereILike(column: string, value: any): this; | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| orWhereIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| orWhereNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| orWhereBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| orWhereNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| orWhereNull(column: string): this; | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| orWhereNotNull(column: string): this; | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| orderBy(column: string, direction?: Direction): this; | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| orderByRaw(): this; | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| latest(column?: string): this; | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| oldest(column?: string): this; | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| offset(number: number): this; | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| limit(number: number): this; | ||
| /** | ||
| * Set the mongo operation in value. | ||
| */ | ||
| private setOperator; | ||
| /** | ||
| * Creates the where clause with where and orWhere. | ||
| */ | ||
| private createWhere; | ||
| /** | ||
| * Creates the aggregation pipeline. | ||
| */ | ||
| private createPipeline; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Is, Json, Exec, Options } from '@athenna/common'; | ||
| import { debug } from '#src/debug'; | ||
| import { Log } from '@athenna/logger'; | ||
| import { ObjectId } from '#src/helpers/ObjectId'; | ||
| import { Driver } from '#src/database/drivers/Driver'; | ||
| import { ModelSchema } from '#src/models/schemas/ModelSchema'; | ||
| import { Transaction } from '#src/database/transactions/Transaction'; | ||
| import { ConnectionFactory } from '#src/factories/ConnectionFactory'; | ||
| import { WrongMethodException } from '#src/exceptions/WrongMethodException'; | ||
| import { MONGO_OPERATIONS_DICTIONARY } from '#src/constants/MongoOperationsDictionary'; | ||
| import { NotConnectedDatabaseException } from '#src/exceptions/NotConnectedDatabaseException'; | ||
| import { NotImplementedMethodException } from '#src/exceptions/NotImplementedMethodException'; | ||
| export class MongoDriver extends Driver { | ||
| constructor() { | ||
| super(...arguments); | ||
| this.primaryKey = '_id'; | ||
| this.session = null; | ||
| /** | ||
| * The where clause used in update queries. | ||
| */ | ||
| this._where = []; | ||
| /** | ||
| * The or where clause used in update queries. | ||
| */ | ||
| this._orWhere = []; | ||
| /** | ||
| * The aggregate pipeline to make mongo queries. | ||
| */ | ||
| this.pipeline = []; | ||
| } | ||
| /** | ||
| * Set the mongo session that should be used by the driver. | ||
| */ | ||
| setSession(session) { | ||
| this.session = session; | ||
| return this; | ||
| } | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| connect(options = {}) { | ||
| options = Options.create(options, { | ||
| force: false, | ||
| saveOnFactory: true, | ||
| connect: true | ||
| }); | ||
| if (!options.connect) { | ||
| return; | ||
| } | ||
| if (this.isConnected && !options.force) { | ||
| return; | ||
| } | ||
| const mongoose = this.getMongoose(); | ||
| const configs = Config.get(`database.connections.${this.connection}`, {}); | ||
| if (configs.debug !== undefined) { | ||
| mongoose.set('debug', configs.debug); | ||
| } | ||
| const mongoOpts = Json.omit(configs, [ | ||
| 'url', | ||
| 'debug', | ||
| 'driver', | ||
| 'validations' | ||
| ]); | ||
| debug('creating new connection using mongoose. options defined: %o', { | ||
| url: configs.url, | ||
| debug: configs.debug, | ||
| ...mongoOpts | ||
| }); | ||
| this.client = mongoose.createConnection(configs.url, mongoOpts); | ||
| this.client.on('connected', () => { | ||
| if (Config.is('rc.bootLogs', true)) { | ||
| Log.channelOrVanilla('application').success(`Successfully connected to ({yellow} ${this.connection}) database connection`); | ||
| } | ||
| }); | ||
| this.isConnected = true; | ||
| this.isSavedOnFactory = options.saveOnFactory; | ||
| if (this.isSavedOnFactory) { | ||
| ConnectionFactory.setClient(this.connection, this.client); | ||
| } | ||
| this.qb = this.query(); | ||
| } | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| async close() { | ||
| if (!this.isConnected) { | ||
| return; | ||
| } | ||
| await this.client.close(); | ||
| this.qb = null; | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.session = null; | ||
| this.isConnected = false; | ||
| ConnectionFactory.setClient(this.connection, null); | ||
| } | ||
| /** | ||
| * Creates a new instance of query builder. | ||
| */ | ||
| query() { | ||
| if (!this.isConnected) { | ||
| throw new NotConnectedDatabaseException(); | ||
| } | ||
| return this.client.collection(this.tableName || 'lock'); | ||
| } | ||
| /** | ||
| * Sync a model schema with database. | ||
| */ | ||
| async sync(schema) { | ||
| const columns = {}; | ||
| const mongoose = await import('mongoose'); | ||
| schema.columns.forEach(column => { | ||
| columns[column.name] = {}; | ||
| if (column.type !== undefined) { | ||
| columns[column.name].type = column.type; | ||
| } | ||
| if (column.isNullable !== undefined) { | ||
| columns[column.name].required = column.isNullable; | ||
| } | ||
| if (column.length !== undefined) { | ||
| columns[column.name].maxLength = column.length; | ||
| } | ||
| if (column.defaultTo !== undefined) { | ||
| columns[column.name].default = column.defaultTo; | ||
| } | ||
| if (column.isIndex !== undefined) { | ||
| columns[column.name].index = column.isIndex; | ||
| } | ||
| if (column.isSparse !== undefined) { | ||
| columns[column.name].sparse = column.isSparse; | ||
| } | ||
| if (column.isUnique !== undefined) { | ||
| columns[column.name].unique = column.isUnique; | ||
| } | ||
| if (columns[column.name].unique || columns[column.name].sparse) { | ||
| columns[column.name].index = true; | ||
| } | ||
| }); | ||
| /** | ||
| * Relations will not be registered because | ||
| * Athenna will handle them instead of mongoose. | ||
| */ | ||
| return this.client | ||
| .model(schema.getModelName(), new mongoose.Schema(columns)) | ||
| .createIndexes(); | ||
| } | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| async startTransaction() { | ||
| await this.client.asPromise(); | ||
| const session = await this.client.startSession(); | ||
| session.startTransaction(); | ||
| return new Transaction(new MongoDriver(this.connection, this.client).setSession(session)); | ||
| } | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| async commitTransaction() { | ||
| await this.client.asPromise(); | ||
| await this.session.commitTransaction(); | ||
| await this.session.endSession(); | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.session = null; | ||
| this.isConnected = false; | ||
| } | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| async rollbackTransaction() { | ||
| await this.client.asPromise(); | ||
| await this.session.abortTransaction(); | ||
| await this.session.endSession(); | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.session = null; | ||
| this.isConnected = false; | ||
| } | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| async runMigrations() { | ||
| throw new NotImplementedMethodException(this.runMigrations.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| async revertMigrations() { | ||
| throw new NotImplementedMethodException(this.revertMigrations.name, 'mongo'); | ||
| } | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| async getDatabases() { | ||
| await this.client.asPromise(); | ||
| const admin = this.client.db.admin(); | ||
| const { databases } = await admin.listDatabases(); | ||
| return databases.map(database => database.name); | ||
| } | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| async getCurrentDatabase() { | ||
| await this.client.asPromise(); | ||
| return this.client.db.databaseName; | ||
| } | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| async hasDatabase(database) { | ||
| await this.client.asPromise(); | ||
| const databases = await this.getDatabases(); | ||
| return databases.includes(database); | ||
| } | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| async createDatabase() { | ||
| throw new NotImplementedMethodException(this.createDatabase.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| async dropDatabase(database) { | ||
| await this.client.asPromise(); | ||
| await this.client.useDb(database).dropDatabase(); | ||
| } | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| async getTables() { | ||
| await this.client.asPromise(); | ||
| const collections = await this.client.db.listCollections().toArray(); | ||
| return collections.map(collection => collection.name); | ||
| } | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| async hasTable(table) { | ||
| await this.client.asPromise(); | ||
| const tables = await this.getTables(); | ||
| return tables.includes(table); | ||
| } | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| async createTable() { | ||
| throw new NotImplementedMethodException(this.createTable.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| async alterTable() { | ||
| throw new NotImplementedMethodException(this.alterTable.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| async dropTable(table) { | ||
| try { | ||
| await this.client.asPromise(); | ||
| await this.client.dropCollection(table); | ||
| } | ||
| catch (err) { | ||
| debug('error happened while dropping table %s in MongoDriver: %o', err); | ||
| } | ||
| } | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| async truncate(table) { | ||
| await this.client.asPromise(); | ||
| const collection = this.client.collection(table); | ||
| await collection.deleteMany({}, { session: this.session }); | ||
| } | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw() { | ||
| throw new NotImplementedMethodException(this.raw.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| async avg(column) { | ||
| await this.client.asPromise(); | ||
| const pipeline = this.createPipeline(); | ||
| pipeline.push({ | ||
| $group: { [this.primaryKey]: null, avg: { $avg: `$${column}` } } | ||
| }); | ||
| pipeline.push({ $project: { [this.primaryKey]: 0, avg: 1 } }); | ||
| const result = await this.qb | ||
| .aggregate(pipeline, { session: this.session }) | ||
| .toArray(); | ||
| if (Is.Empty(result)) { | ||
| return null; | ||
| } | ||
| return `${result[0].avg}`; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async avgDistinct(column) { | ||
| await this.client.asPromise(); | ||
| const pipeline = this.createPipeline(); | ||
| pipeline.push({ | ||
| $group: { [this.primaryKey]: null, set: { $addToSet: `$${column}` } } | ||
| }); | ||
| pipeline.push({ $project: { [this.primaryKey]: 0, avg: { $avg: '$set' } } }); | ||
| const result = await this.qb | ||
| .aggregate(pipeline, { session: this.session }) | ||
| .toArray(); | ||
| if (Is.Empty(result)) { | ||
| return null; | ||
| } | ||
| return `${result[0].avg}`; | ||
| } | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| async max(column) { | ||
| await this.client.asPromise(); | ||
| const pipeline = this.createPipeline(); | ||
| pipeline.push({ | ||
| $group: { [this.primaryKey]: null, max: { $max: `$${column}` } } | ||
| }); | ||
| pipeline.push({ $project: { [this.primaryKey]: 0, max: 1 } }); | ||
| const result = await this.qb | ||
| .aggregate(pipeline, { session: this.session }) | ||
| .toArray(); | ||
| if (Is.Empty(result)) { | ||
| return null; | ||
| } | ||
| return `${result[0].max}`; | ||
| } | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| async min(column) { | ||
| await this.client.asPromise(); | ||
| const pipeline = this.createPipeline(); | ||
| pipeline.push({ | ||
| $group: { [this.primaryKey]: null, min: { $min: `$${column}` } } | ||
| }); | ||
| pipeline.push({ $project: { [this.primaryKey]: 0, min: 1 } }); | ||
| const result = await this.qb | ||
| .aggregate(pipeline, { session: this.session }) | ||
| .toArray(); | ||
| if (Is.Empty(result)) { | ||
| return null; | ||
| } | ||
| return `${result[0].min}`; | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| async sum(column) { | ||
| await this.client.asPromise(); | ||
| const pipeline = this.createPipeline(); | ||
| pipeline.push({ | ||
| $group: { [this.primaryKey]: null, sum: { $sum: `$${column}` } } | ||
| }); | ||
| pipeline.push({ $project: { [this.primaryKey]: 0, sum: 1 } }); | ||
| const result = await this.qb | ||
| .aggregate(pipeline, { session: this.session }) | ||
| .toArray(); | ||
| if (Is.Empty(result)) { | ||
| return null; | ||
| } | ||
| return `${result[0].sum}`; | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column in distinct mode. | ||
| */ | ||
| async sumDistinct(column) { | ||
| await this.client.asPromise(); | ||
| const pipeline = this.createPipeline(); | ||
| pipeline.push({ | ||
| $group: { [this.primaryKey]: null, set: { $addToSet: `$${column}` } } | ||
| }); | ||
| pipeline.push({ $project: { [this.primaryKey]: 0, sum: { $sum: '$set' } } }); | ||
| const result = await this.qb | ||
| .aggregate(pipeline, { session: this.session }) | ||
| .toArray(); | ||
| if (Is.Empty(result)) { | ||
| return null; | ||
| } | ||
| return `${result[0].sum}`; | ||
| } | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| async increment(column) { | ||
| await this.client.asPromise(); | ||
| const where = this.createWhere(); | ||
| await this.qb.updateMany(where, { $inc: { [column]: 1 } }, { session: this.session, upsert: false }); | ||
| } | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| async decrement(column) { | ||
| await this.client.asPromise(); | ||
| const where = this.createWhere(); | ||
| await this.qb.updateMany(where, { $inc: { [column]: -1 } }, { session: this.session, upsert: false }); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async count(column = '*') { | ||
| await this.client.asPromise(); | ||
| const pipeline = this.createPipeline(); | ||
| if (column !== '*') { | ||
| pipeline.push({ $match: { [column]: { $ne: null } } }); | ||
| } | ||
| pipeline.push({ $group: { [this.primaryKey]: null, count: { $sum: 1 } } }); | ||
| pipeline.push({ $project: { [this.primaryKey]: 0, count: 1 } }); | ||
| const result = await this.qb | ||
| .aggregate(pipeline, { session: this.session }) | ||
| .toArray(); | ||
| return `${result[0]?.count || 0}`; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async countDistinct(column) { | ||
| await this.client.asPromise(); | ||
| const pipeline = this.createPipeline(); | ||
| if (column !== '*') { | ||
| pipeline.push({ $match: { [column]: { $ne: null } } }); | ||
| } | ||
| pipeline.push({ | ||
| $group: { [this.primaryKey]: null, set: { $addToSet: `$${column}` } } | ||
| }); | ||
| pipeline.push({ | ||
| $project: { [this.primaryKey]: 0, count: { $size: `$set` } } | ||
| }); | ||
| const [{ count }] = await this.qb | ||
| .aggregate(pipeline, { session: this.session }) | ||
| .toArray(); | ||
| return `${count}`; | ||
| } | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| async find() { | ||
| await this.client.asPromise(); | ||
| const pipeline = this.createPipeline(); | ||
| const data = await this.qb | ||
| .aggregate(pipeline, { session: this.session }) | ||
| .toArray(); | ||
| return data[0]; | ||
| } | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| async findMany() { | ||
| await this.client.asPromise(); | ||
| const pipeline = this.createPipeline(); | ||
| return this.qb | ||
| .aggregate(pipeline, { session: this.session }) | ||
| .toArray(); | ||
| } | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| async paginate(page = { page: 0, limit: 10, resourceUrl: '/' }, limit = 10, resourceUrl = '/') { | ||
| await this.client.asPromise(); | ||
| if (Is.Number(page)) { | ||
| page = { page, limit, resourceUrl }; | ||
| } | ||
| const pipeline = this.createPipeline({ | ||
| clearWhere: false, | ||
| clearOrWhere: false, | ||
| clearPipeline: false | ||
| }); | ||
| pipeline.push({ $group: { [this.primaryKey]: null, count: { $sum: 1 } } }); | ||
| pipeline.push({ $project: { [this.primaryKey]: 0, count: 1 } }); | ||
| const result = await this.qb | ||
| .aggregate(pipeline, { session: this.session }) | ||
| .toArray(); | ||
| const count = result[0]?.count || 0; | ||
| const data = await this.offset(page.page * page.limit) | ||
| .limit(page.limit) | ||
| .findMany(); | ||
| return Exec.pagination(data, count, page); | ||
| } | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| async create(data = {}) { | ||
| if (Is.Array(data)) { | ||
| throw new WrongMethodException('create', 'createMany'); | ||
| } | ||
| await this.client.asPromise(); | ||
| const created = await this.createMany([data]); | ||
| return created[0]; | ||
| } | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| async createMany(data = []) { | ||
| if (!Is.Array(data)) { | ||
| throw new WrongMethodException('createMany', 'create'); | ||
| } | ||
| await this.client.asPromise(); | ||
| const { insertedIds } = await this.qb.insertMany(data, { | ||
| session: this.session | ||
| }); | ||
| const insertedIdsArray = []; | ||
| Object.keys(insertedIds).forEach(key => insertedIdsArray.push(insertedIds[key])); | ||
| return this.whereIn(this.primaryKey, insertedIdsArray).findMany(); | ||
| } | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| async createOrUpdate(data = {}) { | ||
| await this.client.asPromise(); | ||
| const pipeline = this.createPipeline(); | ||
| const hasValue = (await this.qb.aggregate(pipeline, { session: this.session }).toArray())[0]; | ||
| if (hasValue) { | ||
| return this.where(this.primaryKey, hasValue[this.primaryKey]).update(data); | ||
| } | ||
| return this.create(data); | ||
| } | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| async update(data) { | ||
| await this.client.asPromise(); | ||
| const where = this.createWhere({ clearWhere: false, clearOrWhere: false }); | ||
| const pipeline = this.createPipeline(); | ||
| await this.qb.updateMany(where, { $set: data }, { upsert: false, session: this.session }); | ||
| const result = await this.qb | ||
| .aggregate(pipeline, { session: this.session }) | ||
| .toArray(); | ||
| if (result.length === 1) { | ||
| return result[0]; | ||
| } | ||
| return result; | ||
| } | ||
| /** | ||
| * Delete one value in database. | ||
| */ | ||
| async delete() { | ||
| await this.client.asPromise(); | ||
| await this.qb.deleteMany(this.createWhere(), { session: this.session }); | ||
| } | ||
| /** | ||
| * Set the table that this query will be executed. | ||
| */ | ||
| table(table) { | ||
| if (!this.isConnected) { | ||
| throw new NotConnectedDatabaseException(); | ||
| } | ||
| this.tableName = table; | ||
| this.qb = this.query(); | ||
| return this; | ||
| } | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| dump() { | ||
| console.log({ | ||
| where: this._where, | ||
| orWhere: this._orWhere, | ||
| pipeline: this.pipeline | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| select(...columns) { | ||
| if (columns.includes('*')) { | ||
| return this; | ||
| } | ||
| if (!columns.includes('_id')) { | ||
| const isAlreadyHide = !!this.pipeline | ||
| .map(step => { | ||
| if (!step.$project) { | ||
| return false; | ||
| } | ||
| if (!step.$project._id) { | ||
| return false; | ||
| } | ||
| if (step.$project._id === 0) { | ||
| return false; | ||
| } | ||
| return true; | ||
| }) | ||
| .find(value => value === true); | ||
| if (!isAlreadyHide) { | ||
| this.pipeline.push({ $project: { _id: 0 } }); | ||
| } | ||
| } | ||
| const $project = columns.reduce((previous, column) => { | ||
| if (column.includes(`${this.tableName}.`)) { | ||
| column = column.replace(`${this.tableName}.`, ''); | ||
| } | ||
| if (column.includes(' as ')) { | ||
| const [select, alias] = column.split(' as '); | ||
| previous[select] = 0; | ||
| previous[alias] = `$${select}`; | ||
| return previous; | ||
| } | ||
| previous[column] = 1; | ||
| return previous; | ||
| }, {}); | ||
| this.pipeline.push({ $project }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| selectRaw() { | ||
| throw new NotImplementedMethodException(this.selectRaw.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| from() { | ||
| throw new NotImplementedMethodException(this.from.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| fromRaw() { | ||
| throw new NotImplementedMethodException(this.selectRaw.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set a join statement in your query. | ||
| */ | ||
| join(table, column1, operation, column2) { | ||
| let foreignField = column2 || operation || this.primaryKey; | ||
| if (foreignField.includes('.')) { | ||
| foreignField = foreignField.split('.')[1]; | ||
| } | ||
| let localField = column1 || this.primaryKey; | ||
| if (localField.includes('.')) { | ||
| localField = localField.split('.')[1]; | ||
| } | ||
| this.pipeline.push({ | ||
| $lookup: { from: table, localField, foreignField, as: table } | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a left join statement in your query. | ||
| */ | ||
| leftJoin(table, column1, operation, column2) { | ||
| return this.join(table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a right join statement in your query. | ||
| */ | ||
| rightJoin(table, column1, operation, column2) { | ||
| return this.join(table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a cross join statement in your query. | ||
| */ | ||
| crossJoin(table, column1, operation, column2) { | ||
| return this.join(table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a full outer join statement in your query. | ||
| */ | ||
| fullOuterJoin(table, column1, operation, column2) { | ||
| return this.join(table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a left outer join statement in your query. | ||
| */ | ||
| leftOuterJoin(table, column1, operation, column2) { | ||
| return this.join(table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a right outer join statement in your query. | ||
| */ | ||
| rightOuterJoin(table, column1, operation, column2) { | ||
| return this.join(table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| joinRaw() { | ||
| throw new NotImplementedMethodException(this.joinRaw.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| groupBy(...columns) { | ||
| const $group = { [this.primaryKey]: {} }; | ||
| columns.forEach(column => ($group[this.primaryKey][column] = `$${column}`)); | ||
| this.pipeline.push({ $group }); | ||
| this.pipeline.push({ $replaceRoot: { newRoot: `$${this.primaryKey}` } }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| groupByRaw() { | ||
| throw new NotImplementedMethodException(this.groupByRaw.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set a having statement in your query. | ||
| */ | ||
| having(column, operation, value) { | ||
| return this.where(column, operation, value); | ||
| } | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| havingRaw() { | ||
| throw new NotImplementedMethodException(this.havingRaw.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| havingExists() { | ||
| throw new NotImplementedMethodException(this.havingExists.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| havingNotExists() { | ||
| throw new NotImplementedMethodException(this.havingNotExists.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| havingIn(column, values) { | ||
| return this.whereIn(column, values); | ||
| } | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| havingNotIn(column, values) { | ||
| return this.whereNotIn(column, values); | ||
| } | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| havingBetween(column, values) { | ||
| return this.whereBetween(column, values); | ||
| } | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| havingNotBetween(column, values) { | ||
| return this.whereNotBetween(column, values); | ||
| } | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| havingNull(column) { | ||
| return this.whereNull(column); | ||
| } | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| havingNotNull(column) { | ||
| return this.whereNotNull(column); | ||
| } | ||
| /** | ||
| * Set an or having statement in your query. | ||
| */ | ||
| orHaving(column, operation, value) { | ||
| return this.orWhere(column, operation, value); | ||
| } | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| orHavingRaw() { | ||
| throw new NotImplementedMethodException(this.orHavingRaw.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| orHavingExists() { | ||
| throw new NotImplementedMethodException(this.orHavingExists.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| orHavingNotExists() { | ||
| throw new NotImplementedMethodException(this.orHavingNotExists.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| orHavingIn(column, values) { | ||
| return this.orWhereIn(column, values); | ||
| } | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| orHavingNotIn(column, values) { | ||
| return this.orWhereNotIn(column, values); | ||
| } | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| orHavingBetween(column, values) { | ||
| return this.orWhereBetween(column, values); | ||
| } | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| orHavingNotBetween(column, values) { | ||
| return this.orWhereNotBetween(column, values); | ||
| } | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| orHavingNull(column) { | ||
| return this.whereNull(column); | ||
| } | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| orHavingNotNull(column) { | ||
| return this.whereNotNull(column); | ||
| } | ||
| /** | ||
| * Set a where statement in your query. | ||
| */ | ||
| where(statement, operation, value) { | ||
| if (Is.Function(statement)) { | ||
| statement(this); | ||
| return this; | ||
| } | ||
| if (operation === undefined) { | ||
| this._where.push(statement); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this._where.push({ | ||
| [statement]: this.setOperator(operation, '=') | ||
| }); | ||
| return this; | ||
| } | ||
| this._where.push({ [statement]: this.setOperator(value, operation) }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not statement in your query. | ||
| */ | ||
| whereNot(statement, value) { | ||
| return this.where(statement, '<>', value); | ||
| } | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| whereRaw() { | ||
| throw new NotImplementedMethodException(this.whereRaw.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| whereExists() { | ||
| throw new NotImplementedMethodException(this.whereExists.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| whereNotExists() { | ||
| throw new NotImplementedMethodException(this.whereNotExists.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| whereLike(column, value) { | ||
| return this.where(column, 'like', value); | ||
| } | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| whereILike(column, value) { | ||
| return this.where(column, 'ilike', value); | ||
| } | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| whereIn(column, values) { | ||
| values = values.flatMap(value => { | ||
| if (ObjectId.isValidStringOrObject(value)) { | ||
| return [String(value), new ObjectId(value)]; | ||
| } | ||
| return [value]; | ||
| }); | ||
| this._where.push({ [column]: { $in: values } }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| whereNotIn(column, values) { | ||
| values = values.flatMap(value => { | ||
| if (ObjectId.isValidStringOrObject(value)) { | ||
| return [String(value), new ObjectId(value)]; | ||
| } | ||
| return [value]; | ||
| }); | ||
| this._where.push({ [column]: { $nin: values } }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| whereBetween(column, values) { | ||
| this._where.push({ [column]: { $gte: values[0], $lte: values[1] } }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| whereNotBetween(column, values) { | ||
| this._where.push({ | ||
| [column]: { $not: { $gte: values[0], $lte: values[1] } } | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| whereNull(column) { | ||
| this._where.push({ [column]: null }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| whereNotNull(column) { | ||
| this._where.push({ [column]: { $ne: null } }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a or where statement in your query. | ||
| */ | ||
| orWhere(statement, operation, value) { | ||
| if (Is.Function(statement)) { | ||
| statement(this); | ||
| return this; | ||
| } | ||
| if (operation === undefined) { | ||
| this._orWhere.push(statement); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this._orWhere.push({ [statement]: this.setOperator(operation, '=') }); | ||
| return this; | ||
| } | ||
| this._orWhere.push({ [statement]: this.setOperator(value, operation) }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not statement in your query. | ||
| */ | ||
| orWhereNot(statement, value) { | ||
| return this.orWhere(statement, '<>', value); | ||
| } | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| */ | ||
| orWhereRaw() { | ||
| throw new NotImplementedMethodException(this.orWhereRaw.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| orWhereExists() { | ||
| throw new NotImplementedMethodException(this.orWhereExists.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| orWhereNotExists() { | ||
| throw new NotImplementedMethodException(this.orWhereNotExists.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Set an or where like statement in your query. | ||
| */ | ||
| orWhereLike(column, value) { | ||
| return this.orWhere(column, 'like', value); | ||
| } | ||
| /** | ||
| * Set an or where ILike statement in your query. | ||
| */ | ||
| orWhereILike(column, value) { | ||
| return this.orWhere(column, 'ilike', value); | ||
| } | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| orWhereIn(column, values) { | ||
| values = values.flatMap(value => { | ||
| if (ObjectId.isValidStringOrObject(value)) { | ||
| return [String(value), new ObjectId(value)]; | ||
| } | ||
| return [value]; | ||
| }); | ||
| this._orWhere.push({ [column]: { $in: values } }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| orWhereNotIn(column, values) { | ||
| values = values.flatMap(value => { | ||
| if (ObjectId.isValidStringOrObject(value)) { | ||
| return [String(value), new ObjectId(value)]; | ||
| } | ||
| return [value]; | ||
| }); | ||
| this._orWhere.push({ [column]: { $nin: values } }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| orWhereBetween(column, values) { | ||
| this._orWhere.push({ [column]: { $gte: values[0], $lte: values[1] } }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| orWhereNotBetween(column, values) { | ||
| this._orWhere.push({ | ||
| [column]: { $not: { $gte: values[0], $lte: values[1] } } | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| orWhereNull(column) { | ||
| this._orWhere.push({ [column]: null }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| orWhereNotNull(column) { | ||
| this._orWhere.push({ [column]: { $ne: null } }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| orderBy(column, direction = 'ASC') { | ||
| this.pipeline.push({ | ||
| $sort: { [column]: direction.toLowerCase() === 'asc' ? 1 : -1 } | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| orderByRaw() { | ||
| throw new NotImplementedMethodException(this.orderByRaw.name, 'mongo'); | ||
| } | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| latest(column = 'createdAt') { | ||
| return this.orderBy(column, 'DESC'); | ||
| } | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| oldest(column = 'createdAt') { | ||
| return this.orderBy(column, 'ASC'); | ||
| } | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| offset(number) { | ||
| this.pipeline.push({ $skip: number }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| limit(number) { | ||
| this.pipeline.push({ $limit: number }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the mongo operation in value. | ||
| */ | ||
| setOperator(value, operator) { | ||
| if (operator === '=') { | ||
| return value; | ||
| } | ||
| const mongoOperator = MONGO_OPERATIONS_DICTIONARY[operator]; | ||
| const object = { [mongoOperator]: value }; | ||
| if (operator === 'like' || operator === 'ilike') { | ||
| let valueRegexString = value.replace(/%/g, ''); | ||
| if (!value.startsWith('%') && value.endsWith('%')) { | ||
| valueRegexString = `^${valueRegexString}`; | ||
| } | ||
| else if (value.startsWith('%') && !value.endsWith('%')) { | ||
| valueRegexString = `${valueRegexString}$`; | ||
| } | ||
| object[mongoOperator] = new RegExp(valueRegexString); | ||
| } | ||
| if (operator === 'ilike') { | ||
| object.$options = 'i'; | ||
| } | ||
| return object; | ||
| } | ||
| /** | ||
| * Creates the where clause with where and orWhere. | ||
| */ | ||
| createWhere(options = {}) { | ||
| options = Options.create(options, { | ||
| clearWhere: true, | ||
| clearOrWhere: true | ||
| }); | ||
| const where = {}; | ||
| if (!Is.Empty(this._where)) { | ||
| where.$and = Json.copy(this._where).map(condition => { | ||
| const keysToSwap = Object.keys(condition).filter(key => { | ||
| const value = condition[key]; | ||
| if (ObjectId.isValidStringOrObject(value)) { | ||
| return true; | ||
| } | ||
| return false; | ||
| }); | ||
| keysToSwap.forEach(key => { | ||
| if (!condition.$or) { | ||
| condition.$or = []; | ||
| } | ||
| const objectId = condition[key]; | ||
| condition.$or.push({ [key]: String(objectId) }, { [key]: new ObjectId(objectId) }); | ||
| delete condition[key]; | ||
| }); | ||
| return condition; | ||
| }); | ||
| } | ||
| if (!Is.Empty(this._orWhere)) { | ||
| where.$or = Json.copy(this._orWhere).map(condition => { | ||
| const keysToSwap = Object.keys(condition).filter(key => { | ||
| const value = condition[key]; | ||
| if (ObjectId.isValidStringOrObject(value)) { | ||
| return true; | ||
| } | ||
| return false; | ||
| }); | ||
| keysToSwap.forEach(key => { | ||
| if (!condition.$or) { | ||
| condition.$or = []; | ||
| } | ||
| const objectId = condition[key]; | ||
| condition.$or.push({ [key]: String(objectId) }, { [key]: new ObjectId(objectId) }); | ||
| delete condition[key]; | ||
| }); | ||
| return condition; | ||
| }); | ||
| } | ||
| if (options.clearWhere) { | ||
| this._where = []; | ||
| } | ||
| if (options.clearOrWhere) { | ||
| this._orWhere = []; | ||
| } | ||
| return where; | ||
| } | ||
| /** | ||
| * Creates the aggregation pipeline. | ||
| */ | ||
| createPipeline(options = {}) { | ||
| options = Options.create(options, { | ||
| clearWhere: true, | ||
| clearOrWhere: true, | ||
| clearPipeline: true | ||
| }); | ||
| const pipeline = Json.copy(this.pipeline); | ||
| if (options.clearPipeline) { | ||
| this.pipeline = []; | ||
| } | ||
| pipeline.push({ $match: this.createWhere(options) }); | ||
| return pipeline; | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { type PaginatedResponse, type PaginationOptions } from '@athenna/common'; | ||
| import type { Knex } from 'knex'; | ||
| import { Driver } from '#src/database/drivers/Driver'; | ||
| import { Transaction } from '#src/database/transactions/Transaction'; | ||
| import type { ConnectionOptions, Direction, Operations } from '#src/types'; | ||
| export declare class MySqlDriver extends Driver<Knex, Knex.QueryBuilder> { | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| connect(options?: ConnectionOptions): void; | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| close(): Promise<void>; | ||
| /** | ||
| * Creates a new instance of query builder. | ||
| */ | ||
| query(): Knex.QueryBuilder; | ||
| /** | ||
| * Sync a model schema with database. | ||
| */ | ||
| sync(): Promise<void>; | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| startTransaction(): Promise<Transaction<Knex.Transaction, Knex.QueryBuilder>>; | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| commitTransaction(): Promise<void>; | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| rollbackTransaction(): Promise<void>; | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| runMigrations(): Promise<void>; | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| revertMigrations(): Promise<void>; | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| getDatabases(): Promise<string[]>; | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| getCurrentDatabase(): Promise<string | undefined>; | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| hasDatabase(database: string): Promise<boolean>; | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| createDatabase(database: string): Promise<void>; | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| dropDatabase(database: string): Promise<void>; | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| getTables(): Promise<string[]>; | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| hasTable(table: string): Promise<boolean>; | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| createTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>; | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| alterTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>; | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| dropTable(table: string): Promise<void>; | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| truncate(table: string): Promise<void>; | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw<T = any>(sql: string, bindings?: any): T; | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| avg(column: string): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| avgDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| max(column: string): Promise<string>; | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| min(column: string): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| sum(column: string): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column in distinct mode. | ||
| */ | ||
| sumDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| increment(column: string): Promise<void>; | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| decrement(column: string): Promise<void>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| count(column?: string): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| countDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| find<T = any>(): Promise<T>; | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| findMany<T = any>(): Promise<T[]>; | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| paginate<T = any>(page?: PaginationOptions | number, limit?: number, resourceUrl?: string): Promise<PaginatedResponse<T>>; | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| create<T = any>(data?: Partial<T>): Promise<T>; | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| createMany<T = any>(data?: Partial<T>[]): Promise<T[]>; | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| createOrUpdate<T = any>(data?: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| update<T = any>(data: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Delete one value in database. | ||
| */ | ||
| delete(): Promise<void>; | ||
| /** | ||
| * Set the table that this query will be executed. | ||
| */ | ||
| table(table: string): this; | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| dump(): this; | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| select(...columns: string[]): this; | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| selectRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| from(table: string): this; | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| fromRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a join statement in your query. | ||
| */ | ||
| join(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a left join statement in your query. | ||
| */ | ||
| leftJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a right join statement in your query. | ||
| */ | ||
| rightJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a cross join statement in your query. | ||
| */ | ||
| crossJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a full outer join statement in your query. | ||
| */ | ||
| fullOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a left outer join statement in your query. | ||
| */ | ||
| leftOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a right outer join statement in your query. | ||
| */ | ||
| rightOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| joinRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| groupBy(...columns: string[]): this; | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| groupByRaw(sql: string, bindings?: any): this; | ||
| having(column: string): this; | ||
| having(column: string, value: any): this; | ||
| having(column: string, operation: Operations, value: any): this; | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| havingRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| havingExists(closure: (query: MySqlDriver) => void): this; | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| havingNotExists(closure: (query: MySqlDriver) => void): this; | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| havingIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| havingNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| havingBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| havingNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| havingNull(column: string): this; | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| havingNotNull(column: string): this; | ||
| orHaving(column: string): this; | ||
| orHaving(column: string, value: any): this; | ||
| orHaving(column: string, operation: Operations, value: any): this; | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| orHavingRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| orHavingExists(closure: (query: MySqlDriver) => void): this; | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| orHavingNotExists(closure: (query: MySqlDriver) => void): this; | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| orHavingIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| orHavingNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| orHavingBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| orHavingNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| orHavingNull(column: string): this; | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| orHavingNotNull(column: string): this; | ||
| where(statement: Record<string, any>): this; | ||
| where(key: string, value: any): this; | ||
| where(key: string, operation: Operations, value: any): this; | ||
| whereNot(statement: Record<string, any>): this; | ||
| whereNot(key: string, value: any): this; | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| whereRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| whereExists(closure: (query: MySqlDriver) => void): this; | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| whereNotExists(closure: (query: MySqlDriver) => void): this; | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| whereLike(column: string, value: any): this; | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| whereILike(column: string, value: any): this; | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| whereIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| whereNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| whereBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| whereNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| whereNull(column: string): this; | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| whereNotNull(column: string): this; | ||
| orWhere(statement: Record<string, any>): this; | ||
| orWhere(key: string, value: any): this; | ||
| orWhere(key: string, operation: Operations, value: any): this; | ||
| orWhereNot(statement: Record<string, any>): this; | ||
| orWhereNot(key: string, value: any): this; | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| */ | ||
| orWhereRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| orWhereExists(closure: (query: MySqlDriver) => void): this; | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| orWhereNotExists(closure: (query: MySqlDriver) => void): this; | ||
| /** | ||
| * Set an or where like statement in your query. | ||
| */ | ||
| orWhereLike(column: string, value: any): this; | ||
| /** | ||
| * Set an or where ILike statement in your query. | ||
| */ | ||
| orWhereILike(column: string, value: any): this; | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| orWhereIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| orWhereNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| orWhereBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| orWhereNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| orWhereNull(column: string): this; | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| orWhereNotNull(column: string): this; | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| orderBy(column: string, direction?: Direction): this; | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| orderByRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| latest(column?: string): this; | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| oldest(column?: string): this; | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| offset(number: number): this; | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| limit(number: number): this; | ||
| } |
| /* eslint-disable @typescript-eslint/ban-ts-comment */ | ||
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exec, Is, Json, Options } from '@athenna/common'; | ||
| import { debug } from '#src/debug'; | ||
| import { Log } from '@athenna/logger'; | ||
| import { Driver } from '#src/database/drivers/Driver'; | ||
| import { ConnectionFactory } from '#src/factories/ConnectionFactory'; | ||
| import { Transaction } from '#src/database/transactions/Transaction'; | ||
| import { MigrationSource } from '#src/database/migrations/MigrationSource'; | ||
| import { WrongMethodException } from '#src/exceptions/WrongMethodException'; | ||
| import { PROTECTED_QUERY_METHODS } from '#src/constants/ProtectedQueryMethods'; | ||
| import { NotConnectedDatabaseException } from '#src/exceptions/NotConnectedDatabaseException'; | ||
| export class MySqlDriver extends Driver { | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| connect(options = {}) { | ||
| options = Options.create(options, { | ||
| force: false, | ||
| saveOnFactory: true, | ||
| connect: true | ||
| }); | ||
| if (!options.connect) { | ||
| return; | ||
| } | ||
| if (this.isConnected && !options.force) { | ||
| return; | ||
| } | ||
| const knex = this.getKnex(); | ||
| const configs = Config.get(`database.connections.${this.connection}`, {}); | ||
| const knexOpts = { | ||
| client: 'mysql2', | ||
| migrations: { | ||
| tableName: 'migrations' | ||
| }, | ||
| pool: { | ||
| min: 2, | ||
| max: 20, | ||
| acquireTimeoutMillis: 60 * 1000 | ||
| }, | ||
| debug: false, | ||
| useNullAsDefault: false, | ||
| ...Json.omit(configs, ['driver', 'validations']) | ||
| }; | ||
| debug('creating new connection using Knex. options defined: %o', knexOpts); | ||
| if (Config.is('rc.bootLogs', true)) { | ||
| Log.channelOrVanilla('application').success(`Successfully connected to ({yellow} ${this.connection}) database connection`); | ||
| } | ||
| this.client = knex.default(knexOpts); | ||
| this.isConnected = true; | ||
| this.isSavedOnFactory = options.saveOnFactory; | ||
| if (this.isSavedOnFactory) { | ||
| ConnectionFactory.setClient(this.connection, this.client); | ||
| } | ||
| this.qb = this.query(); | ||
| } | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| async close() { | ||
| if (!this.isConnected) { | ||
| return; | ||
| } | ||
| await this.client.destroy(); | ||
| this.qb = null; | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.isConnected = false; | ||
| ConnectionFactory.setClient(this.connection, null); | ||
| } | ||
| /** | ||
| * Creates a new instance of query builder. | ||
| */ | ||
| query() { | ||
| if (!this.isConnected) { | ||
| throw new NotConnectedDatabaseException(); | ||
| } | ||
| const query = this.useSetQB | ||
| ? this.qb.table(this.tableName) | ||
| : this.client.queryBuilder().table(this.tableName); | ||
| const handler = { | ||
| get: (target, propertyKey) => { | ||
| if (PROTECTED_QUERY_METHODS.includes(propertyKey)) { | ||
| this.qb = this.query(); | ||
| } | ||
| return target[propertyKey]; | ||
| } | ||
| }; | ||
| return new Proxy(query, handler); | ||
| } | ||
| /** | ||
| * Sync a model schema with database. | ||
| */ | ||
| async sync() { | ||
| debug(`database sync with ${MySqlDriver.name} is not available yet, use migration instead.`); | ||
| } | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| async startTransaction() { | ||
| const trx = await this.client.transaction(); | ||
| return new Transaction(this.clone().setClient(trx)); | ||
| } | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| async commitTransaction() { | ||
| const client = this.client; | ||
| await client.commit(); | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.isConnected = false; | ||
| } | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| async rollbackTransaction() { | ||
| const client = this.client; | ||
| await client.rollback(); | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.isConnected = false; | ||
| } | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| async runMigrations() { | ||
| await this.client.migrate.latest({ | ||
| migrationSource: new MigrationSource(this.connection) | ||
| }); | ||
| } | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| async revertMigrations() { | ||
| await this.client.migrate.rollback({ | ||
| migrationSource: new MigrationSource(this.connection) | ||
| }); | ||
| } | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| async getDatabases() { | ||
| const [databases] = await this.raw('SHOW DATABASES'); | ||
| return databases.map(database => database.Database); | ||
| } | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| async getCurrentDatabase() { | ||
| return this.client.client.database(); | ||
| } | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| async hasDatabase(database) { | ||
| const databases = await this.getDatabases(); | ||
| return databases.includes(database); | ||
| } | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| async createDatabase(database) { | ||
| await this.raw('CREATE DATABASE IF NOT EXISTS ??', database); | ||
| } | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| async dropDatabase(database) { | ||
| await this.raw('DROP DATABASE IF EXISTS ??', database); | ||
| } | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| async getTables() { | ||
| const [tables] = await this.raw('SELECT table_name FROM information_schema.tables WHERE table_schema = ?', await this.getCurrentDatabase()); | ||
| return tables.map(table => table.TABLE_NAME); | ||
| } | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| async hasTable(table) { | ||
| return this.client.schema.hasTable(table); | ||
| } | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| async createTable(table, closure) { | ||
| await this.client.schema.createTable(table, closure); | ||
| } | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| async alterTable(table, closure) { | ||
| await this.client.schema.alterTable(table, closure); | ||
| } | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| async dropTable(table) { | ||
| await this.client.schema.dropTableIfExists(table); | ||
| } | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| async truncate(table) { | ||
| try { | ||
| await this.raw('SET FOREIGN_KEY_CHECKS = 0'); | ||
| await this.raw('TRUNCATE TABLE ??', table); | ||
| } | ||
| finally { | ||
| await this.raw('SET FOREIGN_KEY_CHECKS = 1'); | ||
| } | ||
| } | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw(sql, bindings) { | ||
| return this.client.raw(sql, bindings); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| async avg(column) { | ||
| const [{ avg }] = await this.qb.avg({ avg: column }); | ||
| return avg; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async avgDistinct(column) { | ||
| const [{ avg }] = await this.qb.avgDistinct({ avg: column }); | ||
| return avg; | ||
| } | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| async max(column) { | ||
| const [{ max }] = await this.qb.max({ max: column }); | ||
| return max; | ||
| } | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| async min(column) { | ||
| const [{ min }] = await this.qb.min({ min: column }); | ||
| return min; | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| async sum(column) { | ||
| const [{ sum }] = await this.qb.sum({ sum: column }); | ||
| return sum; | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column in distinct mode. | ||
| */ | ||
| async sumDistinct(column) { | ||
| const [{ sum }] = await this.qb.sumDistinct({ sum: column }); | ||
| return sum; | ||
| } | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| async increment(column) { | ||
| await this.qb.increment(column); | ||
| } | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| async decrement(column) { | ||
| await this.qb.decrement(column); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async count(column = '*') { | ||
| const [{ count }] = await this.qb.count({ count: column }); | ||
| return `${count}`; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async countDistinct(column) { | ||
| const [{ count }] = await this.qb.countDistinct({ count: column }); | ||
| return `${count}`; | ||
| } | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| async find() { | ||
| return this.qb.first(); | ||
| } | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| async findMany() { | ||
| const data = await this.qb; | ||
| this.qb = this.query(); | ||
| return data; | ||
| } | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| async paginate(page = { page: 0, limit: 10, resourceUrl: '/' }, limit = 10, resourceUrl = '/') { | ||
| if (Is.Number(page)) { | ||
| page = { page, limit, resourceUrl }; | ||
| } | ||
| const [{ count }] = await this.qb | ||
| .clone() | ||
| .clearOrder() | ||
| .clearSelect() | ||
| .count({ count: '*' }); | ||
| const data = await this.offset(page.page * page.limit) | ||
| .limit(page.limit) | ||
| .findMany(); | ||
| return Exec.pagination(data, parseInt(count), page); | ||
| } | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| async create(data = {}) { | ||
| if (Is.Array(data)) { | ||
| throw new WrongMethodException('create', 'createMany'); | ||
| } | ||
| const created = await this.createMany([data]); | ||
| return created[0]; | ||
| } | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| async createMany(data = []) { | ||
| if (!Is.Array(data)) { | ||
| throw new WrongMethodException('createMany', 'create'); | ||
| } | ||
| const ids = []; | ||
| const promises = data.map(data => { | ||
| return this.qb | ||
| .clone() | ||
| .insert(data) | ||
| .then(([id]) => ids.push(data[this.primaryKey] || id)); | ||
| }); | ||
| await Promise.all(promises); | ||
| return this.whereIn(this.primaryKey, ids).findMany(); | ||
| } | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| async createOrUpdate(data = {}) { | ||
| const query = this.qb.clone(); | ||
| const hasValue = await query.first(); | ||
| if (hasValue) { | ||
| await this.qb | ||
| .where(this.primaryKey, hasValue[this.primaryKey]) | ||
| .update(data); | ||
| return this.where(this.primaryKey, hasValue[this.primaryKey]).find(); | ||
| } | ||
| return this.create(data); | ||
| } | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| async update(data) { | ||
| await this.qb.clone().update(data); | ||
| const result = await this.findMany(); | ||
| if (result.length === 1) { | ||
| return result[0]; | ||
| } | ||
| return result; | ||
| } | ||
| /** | ||
| * Delete one value in database. | ||
| */ | ||
| async delete() { | ||
| await this.qb.delete(); | ||
| } | ||
| /** | ||
| * Set the table that this query will be executed. | ||
| */ | ||
| table(table) { | ||
| if (!this.isConnected) { | ||
| throw new NotConnectedDatabaseException(); | ||
| } | ||
| this.tableName = table; | ||
| this.qb = this.query(); | ||
| return this; | ||
| } | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| dump() { | ||
| console.log(this.qb.toSQL().toNative()); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| select(...columns) { | ||
| this.qb.select(...columns); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| selectRaw(sql, bindings) { | ||
| return this.select(this.raw(sql, bindings)); | ||
| } | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| from(table) { | ||
| this.qb.from(table); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| fromRaw(sql, bindings) { | ||
| return this.from(this.raw(sql, bindings)); | ||
| } | ||
| /** | ||
| * Set a join statement in your query. | ||
| */ | ||
| join(table, column1, operation, column2) { | ||
| return this.joinByType('join', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a left join statement in your query. | ||
| */ | ||
| leftJoin(table, column1, operation, column2) { | ||
| return this.joinByType('leftJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a right join statement in your query. | ||
| */ | ||
| rightJoin(table, column1, operation, column2) { | ||
| return this.joinByType('rightJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a cross join statement in your query. | ||
| */ | ||
| crossJoin(table, column1, operation, column2) { | ||
| return this.joinByType('crossJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a full outer join statement in your query. | ||
| */ | ||
| fullOuterJoin(table, column1, operation, column2) { | ||
| // TODO https://github.com/knex/knex/issues/3949 | ||
| return this.joinByType('leftJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a left outer join statement in your query. | ||
| */ | ||
| leftOuterJoin(table, column1, operation, column2) { | ||
| return this.joinByType('leftOuterJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a right outer join statement in your query. | ||
| */ | ||
| rightOuterJoin(table, column1, operation, column2) { | ||
| return this.joinByType('rightOuterJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| joinRaw(sql, bindings) { | ||
| this.qb.joinRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| groupBy(...columns) { | ||
| this.qb.groupBy(...columns); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| groupByRaw(sql, bindings) { | ||
| this.qb.groupByRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having statement in your query. | ||
| */ | ||
| having(column, operation, value) { | ||
| if (operation === undefined) { | ||
| this.qb.having(column); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.having(column, '=', operation); | ||
| return this; | ||
| } | ||
| this.qb.having(column, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| havingRaw(sql, bindings) { | ||
| this.qb.havingRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| havingExists(closure) { | ||
| const driver = this.clone(); | ||
| // @ts-ignore | ||
| this.qb.havingExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| havingNotExists(closure) { | ||
| const driver = this.clone(); | ||
| // @ts-ignore | ||
| this.qb.havingNotExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| havingIn(column, values) { | ||
| this.qb.havingIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| havingNotIn(column, values) { | ||
| this.qb.havingNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| havingBetween(column, values) { | ||
| this.qb.havingBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| havingNotBetween(column, values) { | ||
| this.qb.havingNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| havingNull(column) { | ||
| this.qb.havingNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| havingNotNull(column) { | ||
| this.qb.havingNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having statement in your query. | ||
| */ | ||
| orHaving(column, operation, value) { | ||
| if (operation === undefined) { | ||
| this.qb.orHaving(column); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.orHaving(column, '=', operation); | ||
| return this; | ||
| } | ||
| this.qb.orHaving(column, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| orHavingRaw(sql, bindings) { | ||
| this.qb.orHavingRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| orHavingExists(closure) { | ||
| const driver = this.clone(); | ||
| // @ts-ignore | ||
| this.qb.orHavingExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| orHavingNotExists(closure) { | ||
| const driver = this.clone(); | ||
| // @ts-ignore | ||
| this.qb.orHavingNotExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| orHavingIn(column, values) { | ||
| // @ts-ignore | ||
| this.qb.orHavingIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| orHavingNotIn(column, values) { | ||
| this.qb.orHavingNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| orHavingBetween(column, values) { | ||
| this.qb.orHavingBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| orHavingNotBetween(column, values) { | ||
| this.qb.orHavingNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| orHavingNull(column) { | ||
| // @ts-ignore | ||
| this.qb.orHavingNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| orHavingNotNull(column) { | ||
| // @ts-ignore | ||
| this.qb.orHavingNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where statement in your query. | ||
| */ | ||
| where(statement, operation, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.clone(); | ||
| this.qb.where(function () { | ||
| statement(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| if (operation === undefined) { | ||
| if (Is.Array(statement)) { | ||
| throw new Error('Arrays as statement are not supported.'); | ||
| } | ||
| if (Is.String(statement)) { | ||
| throw new Error(`The value for the "${statement}" column is undefined and where will not work.`); | ||
| } | ||
| this.qb.where(statement); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.where(statement, operation); | ||
| return this; | ||
| } | ||
| this.qb.where(statement, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not statement in your query. | ||
| */ | ||
| whereNot(statement, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.clone(); | ||
| this.qb.whereNot(function () { | ||
| statement(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.whereNot(statement); | ||
| return this; | ||
| } | ||
| this.qb.whereNot(statement, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| whereRaw(sql, bindings) { | ||
| this.qb.whereRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| whereExists(closure) { | ||
| const driver = this.clone(); | ||
| this.qb.whereExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| whereNotExists(closure) { | ||
| const driver = this.clone(); | ||
| this.qb.whereNotExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| whereLike(column, value) { | ||
| this.qb.whereLike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| whereILike(column, value) { | ||
| this.qb.whereILike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| whereIn(column, values) { | ||
| this.qb.whereIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| whereNotIn(column, values) { | ||
| this.qb.whereNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| whereBetween(column, values) { | ||
| this.qb.whereBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| whereNotBetween(column, values) { | ||
| this.qb.whereNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| whereNull(column) { | ||
| this.qb.whereNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| whereNotNull(column) { | ||
| this.qb.whereNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a or where statement in your query. | ||
| */ | ||
| orWhere(statement, operation, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.clone(); | ||
| this.qb.orWhere(function () { | ||
| statement(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| if (operation === undefined) { | ||
| this.qb.orWhere(statement); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.orWhere(statement, operation); | ||
| return this; | ||
| } | ||
| this.qb.orWhere(statement, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not statement in your query. | ||
| */ | ||
| orWhereNot(statement, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.clone(); | ||
| this.qb.orWhereNot(function () { | ||
| statement(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.orWhereNot(statement); | ||
| return this; | ||
| } | ||
| this.qb.orWhereNot(statement, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| */ | ||
| orWhereRaw(sql, bindings) { | ||
| this.qb.orWhereRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| orWhereExists(closure) { | ||
| const driver = this.clone(); | ||
| this.qb.orWhereExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| orWhereNotExists(closure) { | ||
| const driver = this.clone(); | ||
| this.qb.orWhereNotExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where like statement in your query. | ||
| */ | ||
| orWhereLike(column, value) { | ||
| this.qb.orWhereLike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where ILike statement in your query. | ||
| */ | ||
| orWhereILike(column, value) { | ||
| this.qb.orWhereILike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| orWhereIn(column, values) { | ||
| this.qb.orWhereIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| orWhereNotIn(column, values) { | ||
| this.qb.orWhereNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| orWhereBetween(column, values) { | ||
| this.qb.orWhereBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| orWhereNotBetween(column, values) { | ||
| this.qb.orWhereNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| orWhereNull(column) { | ||
| this.qb.orWhereNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| orWhereNotNull(column) { | ||
| this.qb.orWhereNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| orderBy(column, direction = 'ASC') { | ||
| this.qb.orderBy(column, direction.toUpperCase()); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| orderByRaw(sql, bindings) { | ||
| this.qb.orderByRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| latest(column = 'createdAt') { | ||
| return this.orderBy(column, 'DESC'); | ||
| } | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| oldest(column = 'createdAt') { | ||
| return this.orderBy(column, 'ASC'); | ||
| } | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| offset(number) { | ||
| this.qb.offset(number); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| limit(number) { | ||
| this.qb.limit(number); | ||
| return this; | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { type PaginatedResponse, type PaginationOptions } from '@athenna/common'; | ||
| import type { Knex } from 'knex'; | ||
| import { Driver } from '#src/database/drivers/Driver'; | ||
| import { Transaction } from '#src/database/transactions/Transaction'; | ||
| import type { ConnectionOptions, Direction, Operations } from '#src/types'; | ||
| export declare class PostgresDriver extends Driver<Knex, Knex.QueryBuilder> { | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| connect(options?: ConnectionOptions): void; | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| close(): Promise<void>; | ||
| /** | ||
| * Creates a new instance of query builder. | ||
| */ | ||
| query(): Knex.QueryBuilder; | ||
| /** | ||
| * Sync a model schema with database. | ||
| */ | ||
| sync(): Promise<void>; | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| startTransaction(): Promise<Transaction<Knex.Transaction, Knex.QueryBuilder>>; | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| commitTransaction(): Promise<void>; | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| rollbackTransaction(): Promise<void>; | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| runMigrations(): Promise<void>; | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| revertMigrations(): Promise<void>; | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| getDatabases(): Promise<string[]>; | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| getCurrentDatabase(): Promise<string | undefined>; | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| hasDatabase(database: string): Promise<boolean>; | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| createDatabase(database: string): Promise<void>; | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| dropDatabase(database: string): Promise<void>; | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| getTables(): Promise<string[]>; | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| hasTable(table: string): Promise<boolean>; | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| createTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>; | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| alterTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>; | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| dropTable(table: string): Promise<void>; | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| truncate(table: string): Promise<void>; | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw<T = any>(sql: string, bindings?: any): T; | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| avg(column: string): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| avgDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| max(column: string): Promise<string>; | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| min(column: string): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| sum(column: string): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column in distinct mode. | ||
| */ | ||
| sumDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| increment(column: string): Promise<void>; | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| decrement(column: string): Promise<void>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| count(column?: string): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| countDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| find<T = any>(): Promise<T>; | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| findMany<T = any>(): Promise<T[]>; | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| paginate<T = any>(page?: PaginationOptions | number, limit?: number, resourceUrl?: string): Promise<PaginatedResponse<T>>; | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| create<T = any>(data?: Partial<T>): Promise<T>; | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| createMany<T = any>(data?: Partial<T>[]): Promise<T[]>; | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| createOrUpdate<T = any>(data?: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| update<T = any>(data: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Delete one value in database. | ||
| */ | ||
| delete(): Promise<void>; | ||
| /** | ||
| * Set the table that this query will be executed. | ||
| */ | ||
| table(table: string): this; | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| dump(): this; | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| select(...columns: string[]): this; | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| selectRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| from(table: string): this; | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| fromRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a join statement in your query. | ||
| */ | ||
| join(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a left join statement in your query. | ||
| */ | ||
| leftJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a right join statement in your query. | ||
| */ | ||
| rightJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a cross join statement in your query. | ||
| */ | ||
| crossJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a full outer join statement in your query. | ||
| */ | ||
| fullOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a left outer join statement in your query. | ||
| */ | ||
| leftOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a right outer join statement in your query. | ||
| */ | ||
| rightOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| joinRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| groupBy(...columns: string[]): this; | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| groupByRaw(sql: string, bindings?: any): this; | ||
| having(column: string): this; | ||
| having(column: string, value: any): this; | ||
| having(column: string, operation: Operations, value: any): this; | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| havingRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| havingExists(closure: (query: PostgresDriver) => void): this; | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| havingNotExists(closure: (query: PostgresDriver) => void): this; | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| havingIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| havingNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| havingBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| havingNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| havingNull(column: string): this; | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| havingNotNull(column: string): this; | ||
| orHaving(column: string): this; | ||
| orHaving(column: string, value: any): this; | ||
| orHaving(column: string, operation: Operations, value: any): this; | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| orHavingRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| orHavingExists(closure: (query: PostgresDriver) => void): this; | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| orHavingNotExists(closure: (query: PostgresDriver) => void): this; | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| orHavingIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| orHavingNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| orHavingBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| orHavingNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| orHavingNull(column: string): this; | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| orHavingNotNull(column: string): this; | ||
| where(statement: Record<string, any>): this; | ||
| where(key: string, value: any): this; | ||
| where(key: string, operation: Operations, value: any): this; | ||
| whereNot(statement: Record<string, any>): this; | ||
| whereNot(key: string, value: any): this; | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| whereRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| whereExists(closure: (query: PostgresDriver) => void): this; | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| whereNotExists(closure: (query: PostgresDriver) => void): this; | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| whereLike(column: string, value: any): this; | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| whereILike(column: string, value: any): this; | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| whereIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| whereNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| whereBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| whereNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| whereNull(column: string): this; | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| whereNotNull(column: string): this; | ||
| orWhere(statement: Record<string, any>): this; | ||
| orWhere(key: string, value: any): this; | ||
| orWhere(key: string, operation: Operations, value: any): this; | ||
| orWhereNot(statement: Record<string, any>): this; | ||
| orWhereNot(key: string, value: any): this; | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| */ | ||
| orWhereRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| orWhereExists(closure: (query: PostgresDriver) => void): this; | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| orWhereNotExists(closure: (query: PostgresDriver) => void): this; | ||
| /** | ||
| * Set an or where like statement in your query. | ||
| */ | ||
| orWhereLike(column: string, value: any): this; | ||
| /** | ||
| * Set an or where ILike statement in your query. | ||
| */ | ||
| orWhereILike(column: string, value: any): this; | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| orWhereIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| orWhereNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| orWhereBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| orWhereNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| orWhereNull(column: string): this; | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| orWhereNotNull(column: string): this; | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| orderBy(column: string, direction?: Direction): this; | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| orderByRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| latest(column?: string): this; | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| oldest(column?: string): this; | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| offset(number: number): this; | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| limit(number: number): this; | ||
| } |
| /* eslint-disable @typescript-eslint/ban-ts-comment */ | ||
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exec, Is, Json, Options } from '@athenna/common'; | ||
| import { debug } from '#src/debug'; | ||
| import { Log } from '@athenna/logger'; | ||
| import { Driver } from '#src/database/drivers/Driver'; | ||
| import { ConnectionFactory } from '#src/factories/ConnectionFactory'; | ||
| import { Transaction } from '#src/database/transactions/Transaction'; | ||
| import { MigrationSource } from '#src/database/migrations/MigrationSource'; | ||
| import { WrongMethodException } from '#src/exceptions/WrongMethodException'; | ||
| import { PROTECTED_QUERY_METHODS } from '#src/constants/ProtectedQueryMethods'; | ||
| import { NotConnectedDatabaseException } from '#src/exceptions/NotConnectedDatabaseException'; | ||
| export class PostgresDriver extends Driver { | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| connect(options = {}) { | ||
| options = Options.create(options, { | ||
| force: false, | ||
| saveOnFactory: true, | ||
| connect: true | ||
| }); | ||
| if (!options.connect) { | ||
| return; | ||
| } | ||
| if (this.isConnected && !options.force) { | ||
| return; | ||
| } | ||
| const knex = this.getKnex(); | ||
| const configs = Config.get(`database.connections.${this.connection}`, {}); | ||
| const knexOpts = { | ||
| client: 'pg', | ||
| migrations: { | ||
| tableName: 'migrations' | ||
| }, | ||
| pool: { | ||
| min: 2, | ||
| max: 20, | ||
| acquireTimeoutMillis: 60 * 1000 | ||
| }, | ||
| debug: false, | ||
| useNullAsDefault: false, | ||
| ...Json.omit(configs, ['driver', 'validations']) | ||
| }; | ||
| debug('creating new connection using Knex. options defined: %o', knexOpts); | ||
| if (Config.is('rc.bootLogs', true)) { | ||
| Log.channelOrVanilla('application').success(`Successfully connected to ({yellow} ${this.connection}) database connection`); | ||
| } | ||
| this.client = knex.default(knexOpts); | ||
| this.isConnected = true; | ||
| this.isSavedOnFactory = options.saveOnFactory; | ||
| if (this.isSavedOnFactory) { | ||
| ConnectionFactory.setClient(this.connection, this.client); | ||
| } | ||
| this.qb = this.query(); | ||
| } | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| async close() { | ||
| if (!this.isConnected) { | ||
| return; | ||
| } | ||
| await this.client.destroy(); | ||
| this.qb = null; | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.isConnected = false; | ||
| ConnectionFactory.setClient(this.connection, null); | ||
| } | ||
| /** | ||
| * Creates a new instance of query builder. | ||
| */ | ||
| query() { | ||
| if (!this.isConnected) { | ||
| throw new NotConnectedDatabaseException(); | ||
| } | ||
| const query = this.useSetQB | ||
| ? this.qb.table(this.tableName) | ||
| : this.client.queryBuilder().table(this.tableName); | ||
| const handler = { | ||
| get: (target, propertyKey) => { | ||
| if (PROTECTED_QUERY_METHODS.includes(propertyKey)) { | ||
| this.qb = this.query(); | ||
| } | ||
| return target[propertyKey]; | ||
| } | ||
| }; | ||
| return new Proxy(query, handler); | ||
| } | ||
| /** | ||
| * Sync a model schema with database. | ||
| */ | ||
| async sync() { | ||
| debug(`database sync with ${PostgresDriver.name} is not available yet, use migration instead.`); | ||
| } | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| async startTransaction() { | ||
| const trx = await this.client.transaction(); | ||
| return new Transaction(this.clone().setClient(trx)); | ||
| } | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| async commitTransaction() { | ||
| const client = this.client; | ||
| await client.commit(); | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.isConnected = false; | ||
| } | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| async rollbackTransaction() { | ||
| const client = this.client; | ||
| await client.rollback(); | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.isConnected = false; | ||
| } | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| async runMigrations() { | ||
| await this.client.migrate.latest({ | ||
| migrationSource: new MigrationSource(this.connection) | ||
| }); | ||
| } | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| async revertMigrations() { | ||
| await this.client.migrate.rollback({ | ||
| migrationSource: new MigrationSource(this.connection) | ||
| }); | ||
| } | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| async getDatabases() { | ||
| const { rows: databases } = await this.raw('SELECT datname FROM pg_database'); | ||
| return databases.map(database => database.datname); | ||
| } | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| async getCurrentDatabase() { | ||
| return this.client.client.database(); | ||
| } | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| async hasDatabase(database) { | ||
| const databases = await this.getDatabases(); | ||
| return databases.includes(database); | ||
| } | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| async createDatabase(database) { | ||
| /** | ||
| * Catching the error to simulate IF NOT EXISTS | ||
| */ | ||
| try { | ||
| await this.raw('CREATE DATABASE ??', database); | ||
| } | ||
| catch (_err) { } | ||
| } | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| async dropDatabase(database) { | ||
| /** | ||
| * Catching the error to simulate IF EXISTS | ||
| */ | ||
| try { | ||
| await this.raw('DROP DATABASE ??', database); | ||
| } | ||
| catch (_err) { } | ||
| } | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| async getTables() { | ||
| const { rows: tables } = await this.raw('SELECT table_name FROM information_schema.tables WHERE table_schema = current_schema() AND table_catalog = ?', await this.getCurrentDatabase()); | ||
| return tables.map(table => table.table_name); | ||
| } | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| async hasTable(table) { | ||
| return this.client.schema.hasTable(table); | ||
| } | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| async createTable(table, closure) { | ||
| await this.client.schema.createTable(table, closure); | ||
| } | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| async alterTable(table, closure) { | ||
| await this.client.schema.alterTable(table, closure); | ||
| } | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| async dropTable(table) { | ||
| await this.client.schema.dropTableIfExists(table); | ||
| } | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| async truncate(table) { | ||
| await this.raw('TRUNCATE TABLE ?? CASCADE', table); | ||
| } | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw(sql, bindings) { | ||
| return this.client.raw(sql, bindings); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| async avg(column) { | ||
| const [{ avg }] = await this.qb.avg({ avg: column }); | ||
| return avg; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async avgDistinct(column) { | ||
| const [{ avg }] = await this.qb.avgDistinct({ avg: column }); | ||
| return avg; | ||
| } | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| async max(column) { | ||
| const [{ max }] = await this.qb.max({ max: column }); | ||
| return max; | ||
| } | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| async min(column) { | ||
| const [{ min }] = await this.qb.min({ min: column }); | ||
| return min; | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| async sum(column) { | ||
| const [{ sum }] = await this.qb.sum({ sum: column }); | ||
| return sum; | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column in distinct mode. | ||
| */ | ||
| async sumDistinct(column) { | ||
| const [{ sum }] = await this.qb.sumDistinct({ sum: column }); | ||
| return sum; | ||
| } | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| async increment(column) { | ||
| await this.qb.increment(column); | ||
| } | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| async decrement(column) { | ||
| await this.qb.decrement(column); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async count(column = '*') { | ||
| const [{ count }] = await this.qb.count({ count: column }); | ||
| return `${count}`; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async countDistinct(column) { | ||
| const [{ count }] = await this.qb.countDistinct({ count: column }); | ||
| return `${count}`; | ||
| } | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| async find() { | ||
| return this.qb.first(); | ||
| } | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| async findMany() { | ||
| const data = await this.qb; | ||
| this.qb = this.query(); | ||
| return data; | ||
| } | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| async paginate(page = { page: 0, limit: 10, resourceUrl: '/' }, limit = 10, resourceUrl = '/') { | ||
| if (Is.Number(page)) { | ||
| page = { page, limit, resourceUrl }; | ||
| } | ||
| const [{ count }] = await this.qb | ||
| .clone() | ||
| .clearOrder() | ||
| .clearSelect() | ||
| .count({ count: '*' }); | ||
| const data = await this.offset(page.page * page.limit) | ||
| .limit(page.limit) | ||
| .findMany(); | ||
| return Exec.pagination(data, parseInt(count), page); | ||
| } | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| async create(data = {}) { | ||
| if (Is.Array(data)) { | ||
| throw new WrongMethodException('create', 'createMany'); | ||
| } | ||
| const created = await this.createMany([data]); | ||
| return created[0]; | ||
| } | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| async createMany(data = []) { | ||
| if (!Is.Array(data)) { | ||
| throw new WrongMethodException('createMany', 'create'); | ||
| } | ||
| return this.qb.insert(data, '*'); | ||
| } | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| async createOrUpdate(data = {}) { | ||
| const query = this.qb.clone(); | ||
| const hasValue = await query.first(); | ||
| if (hasValue) { | ||
| await this.qb | ||
| .where(this.primaryKey, hasValue[this.primaryKey]) | ||
| .update(data); | ||
| return this.where(this.primaryKey, hasValue[this.primaryKey]).find(); | ||
| } | ||
| return this.create(data); | ||
| } | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| async update(data) { | ||
| await this.qb.clone().update(data); | ||
| const result = await this.findMany(); | ||
| if (result.length === 1) { | ||
| return result[0]; | ||
| } | ||
| return result; | ||
| } | ||
| /** | ||
| * Delete one value in database. | ||
| */ | ||
| async delete() { | ||
| await this.qb.delete(); | ||
| } | ||
| /** | ||
| * Set the table that this query will be executed. | ||
| */ | ||
| table(table) { | ||
| if (!this.isConnected) { | ||
| throw new NotConnectedDatabaseException(); | ||
| } | ||
| this.tableName = table; | ||
| this.qb = this.query(); | ||
| return this; | ||
| } | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| dump() { | ||
| console.log(this.qb.toSQL().toNative()); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| select(...columns) { | ||
| this.qb.select(...columns); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| selectRaw(sql, bindings) { | ||
| return this.select(this.raw(sql, bindings)); | ||
| } | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| from(table) { | ||
| this.qb.from(table); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| fromRaw(sql, bindings) { | ||
| return this.from(this.raw(sql, bindings)); | ||
| } | ||
| /** | ||
| * Set a join statement in your query. | ||
| */ | ||
| join(table, column1, operation, column2) { | ||
| return this.joinByType('join', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a left join statement in your query. | ||
| */ | ||
| leftJoin(table, column1, operation, column2) { | ||
| return this.joinByType('leftJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a right join statement in your query. | ||
| */ | ||
| rightJoin(table, column1, operation, column2) { | ||
| return this.joinByType('rightJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a cross join statement in your query. | ||
| */ | ||
| crossJoin(table, column1, operation, column2) { | ||
| return this.joinByType('crossJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a full outer join statement in your query. | ||
| */ | ||
| fullOuterJoin(table, column1, operation, column2) { | ||
| return this.joinByType('fullOuterJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a left outer join statement in your query. | ||
| */ | ||
| leftOuterJoin(table, column1, operation, column2) { | ||
| return this.joinByType('leftOuterJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a right outer join statement in your query. | ||
| */ | ||
| rightOuterJoin(table, column1, operation, column2) { | ||
| return this.joinByType('rightOuterJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| joinRaw(sql, bindings) { | ||
| this.qb.joinRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| groupBy(...columns) { | ||
| this.qb.groupBy(...columns); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| groupByRaw(sql, bindings) { | ||
| this.qb.groupByRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having statement in your query. | ||
| */ | ||
| having(column, operation, value) { | ||
| if (operation === undefined) { | ||
| this.qb.having(column); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.having(column, '=', operation); | ||
| return this; | ||
| } | ||
| this.qb.having(column, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| havingRaw(sql, bindings) { | ||
| this.qb.havingRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| havingExists(closure) { | ||
| const driver = this.clone(); | ||
| // @ts-ignore | ||
| this.qb.havingExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| havingNotExists(closure) { | ||
| const driver = this.clone(); | ||
| // @ts-ignore | ||
| this.qb.havingNotExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| havingIn(column, values) { | ||
| this.qb.havingIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| havingNotIn(column, values) { | ||
| this.qb.havingNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| havingBetween(column, values) { | ||
| this.qb.havingBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| havingNotBetween(column, values) { | ||
| this.qb.havingNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| havingNull(column) { | ||
| this.qb.havingNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| havingNotNull(column) { | ||
| this.qb.havingNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having statement in your query. | ||
| */ | ||
| orHaving(column, operation, value) { | ||
| if (operation === undefined) { | ||
| this.qb.orHaving(column); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.orHaving(column, '=', operation); | ||
| return this; | ||
| } | ||
| this.qb.orHaving(column, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| orHavingRaw(sql, bindings) { | ||
| this.qb.orHavingRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| orHavingExists(closure) { | ||
| const driver = this.clone(); | ||
| // @ts-ignore | ||
| this.qb.orHavingExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| orHavingNotExists(closure) { | ||
| const driver = this.clone(); | ||
| // @ts-ignore | ||
| this.qb.orHavingNotExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| orHavingIn(column, values) { | ||
| // @ts-ignore | ||
| this.qb.orHavingIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| orHavingNotIn(column, values) { | ||
| this.qb.orHavingNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| orHavingBetween(column, values) { | ||
| this.qb.orHavingBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| orHavingNotBetween(column, values) { | ||
| this.qb.orHavingNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| orHavingNull(column) { | ||
| // @ts-ignore | ||
| this.qb.orHavingNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| orHavingNotNull(column) { | ||
| // @ts-ignore | ||
| this.qb.orHavingNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where statement in your query. | ||
| */ | ||
| where(statement, operation, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.clone(); | ||
| this.qb.where(function () { | ||
| statement(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| if (operation === undefined) { | ||
| if (Is.Array(statement)) { | ||
| throw new Error('Arrays as statement are not supported.'); | ||
| } | ||
| if (Is.String(statement)) { | ||
| throw new Error(`The value for the "${statement}" column is undefined and where will not work.`); | ||
| } | ||
| this.qb.where(statement); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.where(statement, operation); | ||
| return this; | ||
| } | ||
| this.qb.where(statement, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not statement in your query. | ||
| */ | ||
| whereNot(statement, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.clone(); | ||
| this.qb.whereNot(function () { | ||
| statement(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.whereNot(statement); | ||
| return this; | ||
| } | ||
| this.qb.whereNot(statement, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| whereRaw(sql, bindings) { | ||
| this.qb.whereRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| whereExists(closure) { | ||
| const driver = this.clone(); | ||
| this.qb.whereExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| whereNotExists(closure) { | ||
| const driver = this.clone(); | ||
| this.qb.whereNotExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| whereLike(column, value) { | ||
| this.qb.whereLike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| whereILike(column, value) { | ||
| this.qb.whereILike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| whereIn(column, values) { | ||
| this.qb.whereIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| whereNotIn(column, values) { | ||
| this.qb.whereNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| whereBetween(column, values) { | ||
| this.qb.whereBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| whereNotBetween(column, values) { | ||
| this.qb.whereNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| whereNull(column) { | ||
| this.qb.whereNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| whereNotNull(column) { | ||
| this.qb.whereNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a or where statement in your query. | ||
| */ | ||
| orWhere(statement, operation, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.clone(); | ||
| this.qb.orWhere(function () { | ||
| statement(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| if (operation === undefined) { | ||
| this.qb.orWhere(statement); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.orWhere(statement, operation); | ||
| return this; | ||
| } | ||
| this.qb.orWhere(statement, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not statement in your query. | ||
| */ | ||
| orWhereNot(statement, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.clone(); | ||
| this.qb.orWhereNot(function () { | ||
| statement(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.orWhereNot(statement); | ||
| return this; | ||
| } | ||
| this.qb.orWhereNot(statement, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| */ | ||
| orWhereRaw(sql, bindings) { | ||
| this.qb.orWhereRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| orWhereExists(closure) { | ||
| const driver = this.clone(); | ||
| this.qb.orWhereExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| orWhereNotExists(closure) { | ||
| const driver = this.clone(); | ||
| this.qb.orWhereNotExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where like statement in your query. | ||
| */ | ||
| orWhereLike(column, value) { | ||
| this.qb.orWhereLike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where ILike statement in your query. | ||
| */ | ||
| orWhereILike(column, value) { | ||
| this.qb.orWhereILike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| orWhereIn(column, values) { | ||
| this.qb.orWhereIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| orWhereNotIn(column, values) { | ||
| this.qb.orWhereNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| orWhereBetween(column, values) { | ||
| this.qb.orWhereBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| orWhereNotBetween(column, values) { | ||
| this.qb.orWhereNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| orWhereNull(column) { | ||
| this.qb.orWhereNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| orWhereNotNull(column) { | ||
| this.qb.orWhereNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| orderBy(column, direction = 'ASC') { | ||
| this.qb.orderBy(column, direction.toUpperCase()); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| orderByRaw(sql, bindings) { | ||
| this.qb.orderByRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| latest(column = 'createdAt') { | ||
| return this.orderBy(column, 'DESC'); | ||
| } | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| oldest(column = 'createdAt') { | ||
| return this.orderBy(column, 'ASC'); | ||
| } | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| offset(number) { | ||
| this.qb.offset(number); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| limit(number) { | ||
| this.qb.limit(number); | ||
| return this; | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { type PaginatedResponse, type PaginationOptions } from '@athenna/common'; | ||
| import type { Knex } from 'knex'; | ||
| import { Driver } from '#src/database/drivers/Driver'; | ||
| import { Transaction } from '#src/database/transactions/Transaction'; | ||
| import type { ConnectionOptions, Direction, Operations } from '#src/types'; | ||
| export declare class SqliteDriver extends Driver<Knex, Knex.QueryBuilder> { | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| connect(options?: ConnectionOptions): void; | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| close(): Promise<void>; | ||
| /** | ||
| * Creates a new instance of query builder. | ||
| */ | ||
| query(): Knex.QueryBuilder; | ||
| /** | ||
| * Sync a model schema with database. | ||
| */ | ||
| sync(): Promise<void>; | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| startTransaction(): Promise<Transaction<Knex.Transaction, Knex.QueryBuilder>>; | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| commitTransaction(): Promise<void>; | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| rollbackTransaction(): Promise<void>; | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| runMigrations(): Promise<void>; | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| revertMigrations(): Promise<void>; | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| getDatabases(): Promise<string[]>; | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| getCurrentDatabase(): Promise<string | undefined>; | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| hasDatabase(database: string): Promise<boolean>; | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| createDatabase(database: string): Promise<void>; | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| dropDatabase(database: string): Promise<void>; | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| getTables(): Promise<string[]>; | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| hasTable(table: string): Promise<boolean>; | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| createTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>; | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| alterTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>; | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| dropTable(table: string): Promise<void>; | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| truncate(table: string): Promise<void>; | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw<T = any>(sql: string, bindings?: any): T; | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| avg(column: string): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| avgDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| max(column: string): Promise<string>; | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| min(column: string): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| sum(column: string): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column in distinct mode. | ||
| */ | ||
| sumDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| increment(column: string): Promise<void>; | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| decrement(column: string): Promise<void>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| count(column?: string): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| countDistinct(column: string): Promise<string>; | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| find<T = any>(): Promise<T>; | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| findMany<T = any>(): Promise<T[]>; | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| paginate<T = any>(page?: PaginationOptions | number, limit?: number, resourceUrl?: string): Promise<PaginatedResponse<T>>; | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| create<T = any>(data?: Partial<T>): Promise<T>; | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| createMany<T = any>(data?: Partial<T>[]): Promise<T[]>; | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| createOrUpdate<T = any>(data?: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| update<T = any>(data: Partial<T>): Promise<T | T[]>; | ||
| /** | ||
| * Delete one value in database. | ||
| */ | ||
| delete(): Promise<void>; | ||
| /** | ||
| * Set the table that this query will be executed. | ||
| */ | ||
| table(table: string): this; | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| dump(): this; | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| select(...columns: string[]): this; | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| selectRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| from(table: string): this; | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| fromRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a join statement in your query. | ||
| */ | ||
| join(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a left join statement in your query. | ||
| */ | ||
| leftJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a right join statement in your query. | ||
| */ | ||
| rightJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a cross join statement in your query. | ||
| */ | ||
| crossJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a full outer join statement in your query. | ||
| */ | ||
| fullOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a left outer join statement in your query. | ||
| */ | ||
| leftOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a right outer join statement in your query. | ||
| */ | ||
| rightOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this; | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| joinRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| groupBy(...columns: string[]): this; | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| groupByRaw(sql: string, bindings?: any): this; | ||
| having(column: string): this; | ||
| having(column: string, value: any): this; | ||
| having(column: string, operation: Operations, value: any): this; | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| havingRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| havingExists(closure: (query: SqliteDriver) => void): this; | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| havingNotExists(closure: (query: SqliteDriver) => void): this; | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| havingIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| havingNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| havingBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| havingNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| havingNull(column: string): this; | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| havingNotNull(column: string): this; | ||
| orHaving(column: string): this; | ||
| orHaving(column: string, value: any): this; | ||
| orHaving(column: string, operation: Operations, value: any): this; | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| orHavingRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| orHavingExists(closure: (query: SqliteDriver) => void): this; | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| orHavingNotExists(closure: (query: SqliteDriver) => void): this; | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| orHavingIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| orHavingNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| orHavingBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| orHavingNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| orHavingNull(column: string): this; | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| orHavingNotNull(column: string): this; | ||
| where(statement: Record<string, any>): this; | ||
| where(key: string, value: any): this; | ||
| where(key: string, operation: Operations, value: any): this; | ||
| whereNot(statement: Record<string, any>): this; | ||
| whereNot(key: string, value: any): this; | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| whereRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| whereExists(closure: (query: SqliteDriver) => void): this; | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| whereNotExists(closure: (query: SqliteDriver) => void): this; | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| whereLike(column: string, value: any): this; | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| whereILike(column: string, value: any): this; | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| whereIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| whereNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| whereBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| whereNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| whereNull(column: string): this; | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| whereNotNull(column: string): this; | ||
| orWhere(statement: Record<string, any>): this; | ||
| orWhere(key: string, value: any): this; | ||
| orWhere(key: string, operation: Operations, value: any): this; | ||
| orWhereNot(statement: Record<string, any>): this; | ||
| orWhereNot(key: string, value: any): this; | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| */ | ||
| orWhereRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| orWhereExists(closure: (query: SqliteDriver) => void): this; | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| orWhereNotExists(closure: (query: SqliteDriver) => void): this; | ||
| /** | ||
| * Set an or where like statement in your query. | ||
| */ | ||
| orWhereLike(column: string, value: any): this; | ||
| /** | ||
| * Set an or where ILike statement in your query. | ||
| */ | ||
| orWhereILike(column: string, value: any): this; | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| orWhereIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| orWhereNotIn(column: string, values: any[]): this; | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| orWhereBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| orWhereNotBetween(column: string, values: [any, any]): this; | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| orWhereNull(column: string): this; | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| orWhereNotNull(column: string): this; | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| orderBy(column: string, direction?: Direction): this; | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| orderByRaw(sql: string, bindings?: any): this; | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| latest(column?: string): this; | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| oldest(column?: string): this; | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| offset(number: number): this; | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| limit(number: number): this; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| /* eslint-disable @typescript-eslint/ban-ts-comment */ | ||
| import { Exec, Is, Json, Options } from '@athenna/common'; | ||
| import { debug } from '#src/debug'; | ||
| import { Log } from '@athenna/logger'; | ||
| import { Driver } from '#src/database/drivers/Driver'; | ||
| import { ConnectionFactory } from '#src/factories/ConnectionFactory'; | ||
| import { Transaction } from '#src/database/transactions/Transaction'; | ||
| import { MigrationSource } from '#src/database/migrations/MigrationSource'; | ||
| import { WrongMethodException } from '#src/exceptions/WrongMethodException'; | ||
| import { PROTECTED_QUERY_METHODS } from '#src/constants/ProtectedQueryMethods'; | ||
| import { NotConnectedDatabaseException } from '#src/exceptions/NotConnectedDatabaseException'; | ||
| export class SqliteDriver extends Driver { | ||
| /** | ||
| * Connect to database. | ||
| */ | ||
| connect(options = {}) { | ||
| options = Options.create(options, { | ||
| force: false, | ||
| saveOnFactory: true, | ||
| connect: true | ||
| }); | ||
| if (!options.connect) { | ||
| return; | ||
| } | ||
| if (this.isConnected && !options.force) { | ||
| return; | ||
| } | ||
| const knex = this.getKnex(); | ||
| const configs = Config.get(`database.connections.${this.connection}`, {}); | ||
| const knexOpts = { | ||
| client: 'better-sqlite3', | ||
| migrations: { | ||
| tableName: 'migrations' | ||
| }, | ||
| pool: { | ||
| min: 2, | ||
| max: 20, | ||
| acquireTimeoutMillis: 60 * 1000 | ||
| }, | ||
| debug: false, | ||
| useNullAsDefault: false, | ||
| ...Json.omit(configs, ['driver', 'validations']) | ||
| }; | ||
| debug('creating new connection using Knex. options defined: %o', knexOpts); | ||
| if (Config.is('rc.bootLogs', true)) { | ||
| Log.channelOrVanilla('application').success(`Successfully connected to ({yellow} ${this.connection}) database connection`); | ||
| } | ||
| this.client = knex.default(knexOpts); | ||
| this.isConnected = true; | ||
| this.isSavedOnFactory = options.saveOnFactory; | ||
| if (this.isSavedOnFactory) { | ||
| ConnectionFactory.setClient(this.connection, this.client); | ||
| } | ||
| this.qb = this.query(); | ||
| } | ||
| /** | ||
| * Close the connection with database in this instance. | ||
| */ | ||
| async close() { | ||
| if (!this.isConnected) { | ||
| return; | ||
| } | ||
| await this.client.destroy(); | ||
| this.qb = null; | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.isConnected = false; | ||
| ConnectionFactory.setClient(this.connection, null); | ||
| } | ||
| /** | ||
| * Creates a new instance of query builder. | ||
| */ | ||
| query() { | ||
| if (!this.isConnected) { | ||
| throw new NotConnectedDatabaseException(); | ||
| } | ||
| const query = this.useSetQB | ||
| ? this.qb.table(this.tableName) | ||
| : this.client.queryBuilder().table(this.tableName); | ||
| const handler = { | ||
| get: (target, propertyKey) => { | ||
| if (PROTECTED_QUERY_METHODS.includes(propertyKey)) { | ||
| this.qb = this.query(); | ||
| } | ||
| return target[propertyKey]; | ||
| } | ||
| }; | ||
| return new Proxy(query, handler); | ||
| } | ||
| /** | ||
| * Sync a model schema with database. | ||
| */ | ||
| async sync() { | ||
| debug(`database sync with ${SqliteDriver.name} is not available yet, use migration instead.`); | ||
| } | ||
| /** | ||
| * Create a new transaction. | ||
| */ | ||
| async startTransaction() { | ||
| const trx = await this.client.transaction(); | ||
| return new Transaction(this.clone().setClient(trx)); | ||
| } | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| async commitTransaction() { | ||
| const client = this.client; | ||
| await client.commit(); | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.isConnected = false; | ||
| } | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| async rollbackTransaction() { | ||
| const client = this.client; | ||
| await client.rollback(); | ||
| this.tableName = null; | ||
| this.client = null; | ||
| this.isConnected = false; | ||
| } | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| async runMigrations() { | ||
| await this.client.migrate.latest({ | ||
| migrationSource: new MigrationSource(this.connection) | ||
| }); | ||
| } | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| async revertMigrations() { | ||
| await this.client.migrate.rollback({ | ||
| migrationSource: new MigrationSource(this.connection) | ||
| }); | ||
| } | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| async getDatabases() { | ||
| const databases = await this.raw('PRAGMA database_list'); | ||
| return databases.map(database => database.name); | ||
| } | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| async getCurrentDatabase() { | ||
| return this.client.client.database(); | ||
| } | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| async hasDatabase(database) { | ||
| const databases = await this.getDatabases(); | ||
| return databases.includes(database); | ||
| } | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| async createDatabase(database) { | ||
| /** | ||
| * Catching the error to simulate IF NOT EXISTS | ||
| */ | ||
| try { | ||
| await this.raw('CREATE DATABASE ??', database); | ||
| } | ||
| catch (_err) { } | ||
| } | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| async dropDatabase(database) { | ||
| /** | ||
| * Catching the error to simulate IF EXISTS | ||
| */ | ||
| try { | ||
| await this.raw('DROP DATABASE ??', database); | ||
| } | ||
| catch (_err) { } | ||
| } | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| async getTables() { | ||
| const tables = await this.raw("SELECT name FROM sqlite_schema WHERE type = 'table' AND name NOT LIKE 'sqlite_%'", await this.getCurrentDatabase()); | ||
| return tables.map(table => table.name); | ||
| } | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| async hasTable(table) { | ||
| return this.client.schema.hasTable(table); | ||
| } | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| async createTable(table, closure) { | ||
| await this.client.schema.createTable(table, closure); | ||
| } | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| async alterTable(table, closure) { | ||
| await this.client.schema.alterTable(table, closure); | ||
| } | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| async dropTable(table) { | ||
| await this.client.schema.dropTableIfExists(table); | ||
| } | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| async truncate(table) { | ||
| await this.raw('DELETE FROM ??', table); | ||
| } | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw(sql, bindings) { | ||
| return this.client.raw(sql, bindings); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| async avg(column) { | ||
| const [{ avg }] = await this.qb.avg({ avg: column }); | ||
| return avg; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async avgDistinct(column) { | ||
| const [{ avg }] = await this.qb.avgDistinct({ avg: column }); | ||
| return avg; | ||
| } | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| async max(column) { | ||
| const [{ max }] = await this.qb.max({ max: column }); | ||
| return max; | ||
| } | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| async min(column) { | ||
| const [{ min }] = await this.qb.min({ min: column }); | ||
| return min; | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| async sum(column) { | ||
| const [{ sum }] = await this.qb.sum({ sum: column }); | ||
| return sum; | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column in distinct mode. | ||
| */ | ||
| async sumDistinct(column) { | ||
| const [{ sum }] = await this.qb.sumDistinct({ sum: column }); | ||
| return sum; | ||
| } | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| async increment(column) { | ||
| await this.qb.increment(column); | ||
| } | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| async decrement(column) { | ||
| await this.qb.decrement(column); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async count(column = '*') { | ||
| const [{ count }] = await this.qb.count({ count: column }); | ||
| return `${count}`; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async countDistinct(column) { | ||
| const [{ count }] = await this.qb.countDistinct({ count: column }); | ||
| return `${count}`; | ||
| } | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| async find() { | ||
| return this.qb.first(); | ||
| } | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| async findMany() { | ||
| const data = await this.qb; | ||
| this.qb = this.query(); | ||
| return data; | ||
| } | ||
| /** | ||
| * Find many values in database and return as paginated response. | ||
| */ | ||
| async paginate(page = { page: 0, limit: 10, resourceUrl: '/' }, limit = 10, resourceUrl = '/') { | ||
| if (Is.Number(page)) { | ||
| page = { page, limit, resourceUrl }; | ||
| } | ||
| const [{ count }] = await this.qb | ||
| .clone() | ||
| .clearOrder() | ||
| .clearSelect() | ||
| .count({ count: '*' }); | ||
| const data = await this.offset(page.page * page.limit) | ||
| .limit(page.limit) | ||
| .findMany(); | ||
| return Exec.pagination(data, parseInt(count), page); | ||
| } | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| async create(data = {}) { | ||
| if (Is.Array(data)) { | ||
| throw new WrongMethodException('create', 'createMany'); | ||
| } | ||
| const created = await this.createMany([data]); | ||
| return created[0]; | ||
| } | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| async createMany(data = []) { | ||
| if (!Is.Array(data)) { | ||
| throw new WrongMethodException('createMany', 'create'); | ||
| } | ||
| return this.qb.insert(data, '*'); | ||
| } | ||
| /** | ||
| * Create data or update if already exists. | ||
| */ | ||
| async createOrUpdate(data = {}) { | ||
| const query = this.qb.clone(); | ||
| const hasValue = await query.first(); | ||
| if (hasValue) { | ||
| await this.qb | ||
| .where(this.primaryKey, hasValue[this.primaryKey]) | ||
| .update(data); | ||
| return this.where(this.primaryKey, hasValue[this.primaryKey]).find(); | ||
| } | ||
| return this.create(data); | ||
| } | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| async update(data) { | ||
| await this.qb.clone().update(data); | ||
| const result = await this.findMany(); | ||
| if (result.length === 1) { | ||
| return result[0]; | ||
| } | ||
| return result; | ||
| } | ||
| /** | ||
| * Delete one value in database. | ||
| */ | ||
| async delete() { | ||
| await this.qb.delete(); | ||
| } | ||
| /** | ||
| * Set the table that this query will be executed. | ||
| */ | ||
| table(table) { | ||
| if (!this.isConnected) { | ||
| throw new NotConnectedDatabaseException(); | ||
| } | ||
| this.tableName = table; | ||
| this.qb = this.query(); | ||
| return this; | ||
| } | ||
| /** | ||
| * Log in console the actual query built. | ||
| */ | ||
| dump() { | ||
| console.log(this.qb.toSQL().toNative()); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| select(...columns) { | ||
| this.qb.select(...columns); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query raw. | ||
| */ | ||
| selectRaw(sql, bindings) { | ||
| return this.select(this.raw(sql, bindings)); | ||
| } | ||
| /** | ||
| * Set the table that should be used on query. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| from(table) { | ||
| this.qb.from(table); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the table that should be used on query raw. | ||
| * Different from `table()` method, this method | ||
| * doesn't change the driver table. | ||
| */ | ||
| fromRaw(sql, bindings) { | ||
| return this.from(this.raw(sql, bindings)); | ||
| } | ||
| /** | ||
| * Set a join statement in your query. | ||
| */ | ||
| join(table, column1, operation, column2) { | ||
| return this.joinByType('join', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a left join statement in your query. | ||
| */ | ||
| leftJoin(table, column1, operation, column2) { | ||
| return this.joinByType('leftJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a right join statement in your query. | ||
| */ | ||
| rightJoin(table, column1, operation, column2) { | ||
| return this.joinByType('rightJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a cross join statement in your query. | ||
| */ | ||
| crossJoin(table, column1, operation, column2) { | ||
| return this.joinByType('crossJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a full outer join statement in your query. | ||
| */ | ||
| fullOuterJoin(table, column1, operation, column2) { | ||
| return this.joinByType('fullOuterJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a left outer join statement in your query. | ||
| */ | ||
| leftOuterJoin(table, column1, operation, column2) { | ||
| return this.joinByType('leftOuterJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a right outer join statement in your query. | ||
| */ | ||
| rightOuterJoin(table, column1, operation, column2) { | ||
| return this.joinByType('rightOuterJoin', table, column1, operation, column2); | ||
| } | ||
| /** | ||
| * Set a join raw statement in your query. | ||
| */ | ||
| joinRaw(sql, bindings) { | ||
| this.qb.joinRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| groupBy(...columns) { | ||
| this.qb.groupBy(...columns); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a group by raw statement in your query. | ||
| */ | ||
| groupByRaw(sql, bindings) { | ||
| this.qb.groupByRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having statement in your query. | ||
| */ | ||
| having(column, operation, value) { | ||
| if (operation === undefined) { | ||
| this.qb.having(column); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.having(column, '=', operation); | ||
| return this; | ||
| } | ||
| this.qb.having(column, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having raw statement in your query. | ||
| */ | ||
| havingRaw(sql, bindings) { | ||
| this.qb.havingRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having exists statement in your query. | ||
| */ | ||
| havingExists(closure) { | ||
| const driver = this.clone(); | ||
| // @ts-ignore | ||
| this.qb.havingExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not exists statement in your query. | ||
| */ | ||
| havingNotExists(closure) { | ||
| const driver = this.clone(); | ||
| // @ts-ignore | ||
| this.qb.havingNotExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| havingIn(column, values) { | ||
| this.qb.havingIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| havingNotIn(column, values) { | ||
| this.qb.havingNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| havingBetween(column, values) { | ||
| this.qb.havingBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| havingNotBetween(column, values) { | ||
| this.qb.havingNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| havingNull(column) { | ||
| this.qb.havingNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| havingNotNull(column) { | ||
| this.qb.havingNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having statement in your query. | ||
| */ | ||
| orHaving(column, operation, value) { | ||
| if (operation === undefined) { | ||
| this.qb.orHaving(column); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.orHaving(column, '=', operation); | ||
| return this; | ||
| } | ||
| this.qb.orHaving(column, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having raw statement in your query. | ||
| */ | ||
| orHavingRaw(sql, bindings) { | ||
| this.qb.orHavingRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having exists statement in your query. | ||
| */ | ||
| orHavingExists(closure) { | ||
| const driver = this.clone(); | ||
| // @ts-ignore | ||
| this.qb.orHavingExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not exists statement in your query. | ||
| */ | ||
| orHavingNotExists(closure) { | ||
| const driver = this.clone(); | ||
| // @ts-ignore | ||
| this.qb.orHavingNotExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having in statement in your query. | ||
| */ | ||
| orHavingIn(column, values) { | ||
| // @ts-ignore | ||
| this.qb.orHavingIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not in statement in your query. | ||
| */ | ||
| orHavingNotIn(column, values) { | ||
| this.qb.orHavingNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having between statement in your query. | ||
| */ | ||
| orHavingBetween(column, values) { | ||
| this.qb.orHavingBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not between statement in your query. | ||
| */ | ||
| orHavingNotBetween(column, values) { | ||
| this.qb.orHavingNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having null statement in your query. | ||
| */ | ||
| orHavingNull(column) { | ||
| // @ts-ignore | ||
| this.qb.orHavingNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or having not null statement in your query. | ||
| */ | ||
| orHavingNotNull(column) { | ||
| // @ts-ignore | ||
| this.qb.orHavingNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where statement in your query. | ||
| */ | ||
| where(statement, operation, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.clone(); | ||
| this.qb.where(function () { | ||
| statement(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| if (operation === undefined) { | ||
| if (Is.Array(statement)) { | ||
| throw new Error('Arrays as statement are not supported.'); | ||
| } | ||
| if (Is.String(statement)) { | ||
| throw new Error(`The value for the "${statement}" column is undefined and where will not work.`); | ||
| } | ||
| this.qb.where(statement); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.where(statement, operation); | ||
| return this; | ||
| } | ||
| this.qb.where(statement, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not statement in your query. | ||
| */ | ||
| whereNot(statement, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.clone(); | ||
| this.qb.whereNot(function () { | ||
| statement(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.whereNot(statement); | ||
| return this; | ||
| } | ||
| this.qb.whereNot(statement, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where raw statement in your query. | ||
| */ | ||
| whereRaw(sql, bindings) { | ||
| this.qb.whereRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where exists statement in your query. | ||
| */ | ||
| whereExists(closure) { | ||
| const driver = this.clone(); | ||
| this.qb.whereExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not exists statement in your query. | ||
| */ | ||
| whereNotExists(closure) { | ||
| const driver = this.clone(); | ||
| this.qb.whereNotExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| whereLike(column, value) { | ||
| this.qb.whereLike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| whereILike(column, value) { | ||
| this.qb.whereLike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| whereIn(column, values) { | ||
| this.qb.whereIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| whereNotIn(column, values) { | ||
| this.qb.whereNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| whereBetween(column, values) { | ||
| this.qb.whereBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| whereNotBetween(column, values) { | ||
| this.qb.whereNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| whereNull(column) { | ||
| this.qb.whereNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| whereNotNull(column) { | ||
| this.qb.whereNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a or where statement in your query. | ||
| */ | ||
| orWhere(statement, operation, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.clone(); | ||
| this.qb.orWhere(function () { | ||
| statement(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| if (operation === undefined) { | ||
| this.qb.orWhere(statement); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.orWhere(statement, operation); | ||
| return this; | ||
| } | ||
| this.qb.orWhere(statement, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not statement in your query. | ||
| */ | ||
| orWhereNot(statement, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.clone(); | ||
| this.qb.orWhereNot(function () { | ||
| statement(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| if (value === undefined) { | ||
| this.qb.orWhereNot(statement); | ||
| return this; | ||
| } | ||
| this.qb.orWhereNot(statement, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a or where raw statement in your query. | ||
| */ | ||
| orWhereRaw(sql, bindings) { | ||
| this.qb.orWhereRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where exists statement in your query. | ||
| */ | ||
| orWhereExists(closure) { | ||
| const driver = this.clone(); | ||
| this.qb.orWhereExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not exists statement in your query. | ||
| */ | ||
| orWhereNotExists(closure) { | ||
| const driver = this.clone(); | ||
| this.qb.orWhereNotExists(function () { | ||
| closure(driver.setQueryBuilder(this, { useSetQB: true })); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where like statement in your query. | ||
| */ | ||
| orWhereLike(column, value) { | ||
| this.qb.orWhereLike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where ILike statement in your query. | ||
| */ | ||
| orWhereILike(column, value) { | ||
| this.qb.orWhereLike(column, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where in statement in your query. | ||
| */ | ||
| orWhereIn(column, values) { | ||
| this.qb.orWhereIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not in statement in your query. | ||
| */ | ||
| orWhereNotIn(column, values) { | ||
| this.qb.orWhereNotIn(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where between statement in your query. | ||
| */ | ||
| orWhereBetween(column, values) { | ||
| this.qb.orWhereBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not between statement in your query. | ||
| */ | ||
| orWhereNotBetween(column, values) { | ||
| this.qb.orWhereNotBetween(column, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where null statement in your query. | ||
| */ | ||
| orWhereNull(column) { | ||
| this.qb.orWhereNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an or where not null statement in your query. | ||
| */ | ||
| orWhereNotNull(column) { | ||
| this.qb.orWhereNotNull(column); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| orderBy(column, direction = 'ASC') { | ||
| this.qb.orderBy(column, direction.toUpperCase()); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by raw statement in your query. | ||
| */ | ||
| orderByRaw(sql, bindings) { | ||
| this.qb.orderByRaw(sql, bindings); | ||
| return this; | ||
| } | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| latest(column = 'createdAt') { | ||
| return this.orderBy(column, 'DESC'); | ||
| } | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| oldest(column = 'createdAt') { | ||
| return this.orderBy(column, 'ASC'); | ||
| } | ||
| /** | ||
| * Set the skip number in your query. | ||
| */ | ||
| offset(number) { | ||
| this.qb.offset(number); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the limit number in your query. | ||
| */ | ||
| limit(number) { | ||
| this.qb.limit(number); | ||
| return this; | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { DatabaseImpl } from '#src/database/DatabaseImpl'; | ||
| export declare abstract class BaseMigration { | ||
| /** | ||
| * Define the database connection that the | ||
| * migration will use. | ||
| */ | ||
| static connection(): string; | ||
| /** | ||
| * Run the migrations. | ||
| */ | ||
| abstract up(db: DatabaseImpl): Promise<void>; | ||
| /** | ||
| * Reverse the migrations. | ||
| */ | ||
| abstract down(db: DatabaseImpl): Promise<void>; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Config } from '@athenna/config'; | ||
| export class BaseMigration { | ||
| /** | ||
| * Define the database connection that the | ||
| * migration will use. | ||
| */ | ||
| static connection() { | ||
| return Config.get('database.default'); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { BaseMigration } from '#src/database/migrations/BaseMigration'; | ||
| type Source = { | ||
| name: string; | ||
| Migration: new (...args: any[]) => BaseMigration; | ||
| }; | ||
| export declare class MigrationSource { | ||
| connection: any; | ||
| constructor(connection: string); | ||
| /** | ||
| * Verify if migration is able to run by connection. | ||
| */ | ||
| private isAbleToRun; | ||
| /** | ||
| * Get all the migrations from migrations path and import | ||
| * as modules. This method will be used by "getMigration" | ||
| * method later to get the migrations "up"/"down" methods. | ||
| */ | ||
| getMigrations(): Promise<Source[]>; | ||
| /** | ||
| * Get the migration name that will be used to set in | ||
| * migrations table. | ||
| */ | ||
| getMigrationName(source: Source): string; | ||
| /** | ||
| * Creates a new migration instance and return the up/down | ||
| * methods in object. | ||
| */ | ||
| getMigration(source: Source): Promise<{ | ||
| up: (knex: any) => any; | ||
| down: (knex: any) => any; | ||
| }>; | ||
| } | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { debug } from '#src/debug'; | ||
| import { Module, Path } from '@athenna/common'; | ||
| import { DatabaseImpl } from '#src/database/DatabaseImpl'; | ||
| import { ConnectionFactory } from '#src/factories/ConnectionFactory'; | ||
| export class MigrationSource { | ||
| constructor(connection) { | ||
| this.connection = null; | ||
| this.connection = connection; | ||
| } | ||
| /** | ||
| * Verify if migration is able to run by connection. | ||
| */ | ||
| isAbleToRun(migration) { | ||
| return migration.connection() === this.connection; | ||
| } | ||
| /** | ||
| * Get all the migrations from migrations path and import | ||
| * as modules. This method will be used by "getMigration" | ||
| * method later to get the migrations "up"/"down" methods. | ||
| */ | ||
| async getMigrations() { | ||
| const migrations = []; | ||
| const files = await Module.getAllJSFilesFrom(Path.migrations()); | ||
| for (const file of files) { | ||
| const Migration = await Module.getFrom(file.path); | ||
| if (this.isAbleToRun(Migration)) { | ||
| migrations.push({ name: file.base, Migration }); | ||
| } | ||
| } | ||
| return migrations; | ||
| } | ||
| /** | ||
| * Get the migration name that will be used to set in | ||
| * migrations table. | ||
| */ | ||
| getMigrationName(source) { | ||
| return source.name; | ||
| } | ||
| /** | ||
| * Creates a new migration instance and return the up/down | ||
| * methods in object. | ||
| */ | ||
| async getMigration(source) { | ||
| const migration = new source.Migration(); | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| const connection = source.Migration.connection(); | ||
| const database = new DatabaseImpl({ connect: false }); | ||
| debug('configuring database connection %s to run migration %s', connection, source.Migration.name); | ||
| database.connectionName = connection; | ||
| database.driver = ConnectionFactory.fabricate(connection); | ||
| const bind = (method, knex) => { | ||
| database.driver = database.driver.setClient(knex); | ||
| return migration[method].bind(migration)(database); | ||
| }; | ||
| return { | ||
| up: knex => bind('up', knex), | ||
| down: knex => bind('down', knex) | ||
| }; | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { type DatabaseImpl } from '#src/database/DatabaseImpl'; | ||
| export declare abstract class BaseSeeder { | ||
| /** | ||
| * Run the database seeders. | ||
| */ | ||
| abstract run(db?: DatabaseImpl): void | Promise<void>; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import {} from '#src/database/DatabaseImpl'; | ||
| export class BaseSeeder { | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { Knex } from 'knex'; | ||
| import { Macroable } from '@athenna/common'; | ||
| import type { Driver } from '#src/database/drivers/Driver'; | ||
| import { QueryBuilder } from '#src/database/builders/QueryBuilder'; | ||
| export declare class Transaction<Client = any, QB = any> extends Macroable { | ||
| /** | ||
| * The drivers responsible for handling database operations. | ||
| */ | ||
| driver: Driver<Client, QB>; | ||
| /** | ||
| * Creates a new instance of transaction. | ||
| */ | ||
| constructor(driver: Driver); | ||
| /** | ||
| * Return the client of driver. | ||
| */ | ||
| getClient(): Client; | ||
| /** | ||
| * Return the query builder of driver. | ||
| */ | ||
| getQueryBuilder(): QB; | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| commitTransaction(): Promise<void>; | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| rollbackTransaction(): Promise<void>; | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| runMigrations(): Promise<void>; | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| revertMigrations(): Promise<void>; | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| getDatabases(): Promise<string[]>; | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| getCurrentDatabase(): Promise<string | undefined>; | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| hasDatabase(database: string): Promise<boolean>; | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| createDatabase(database: string): Promise<void>; | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| dropDatabase(database: string): Promise<void>; | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| getTables(): Promise<string[]>; | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| hasTable(table: string): Promise<boolean>; | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| createTable(table: string, closure?: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>; | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| alterTable(table: string, closure?: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>; | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| dropTable(table: string): Promise<void>; | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| truncate(table: string): Promise<void>; | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw<T = any>(sql: string, bindings?: any): Knex.Raw<T>; | ||
| /** | ||
| * Creates a new instance of QueryBuilder for this table. | ||
| */ | ||
| table(table: string | any): QueryBuilder; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Macroable } from '@athenna/common'; | ||
| import { QueryBuilder } from '#src/database/builders/QueryBuilder'; | ||
| export class Transaction extends Macroable { | ||
| /** | ||
| * Creates a new instance of transaction. | ||
| */ | ||
| constructor(driver) { | ||
| super(); | ||
| /** | ||
| * The drivers responsible for handling database operations. | ||
| */ | ||
| this.driver = null; | ||
| this.driver = driver; | ||
| } | ||
| /** | ||
| * Return the client of driver. | ||
| */ | ||
| getClient() { | ||
| return this.driver.getClient(); | ||
| } | ||
| /** | ||
| * Return the query builder of driver. | ||
| */ | ||
| getQueryBuilder() { | ||
| return this.driver.getQueryBuilder(); | ||
| } | ||
| /** | ||
| * Commit the transaction. | ||
| */ | ||
| async commitTransaction() { | ||
| return this.driver.commitTransaction(); | ||
| } | ||
| /** | ||
| * Rollback the transaction. | ||
| */ | ||
| async rollbackTransaction() { | ||
| return this.driver.rollbackTransaction(); | ||
| } | ||
| /** | ||
| * Run database migrations. | ||
| */ | ||
| async runMigrations() { | ||
| await this.driver.runMigrations(); | ||
| } | ||
| /** | ||
| * Revert database migrations. | ||
| */ | ||
| async revertMigrations() { | ||
| await this.driver.revertMigrations(); | ||
| } | ||
| /** | ||
| * List all databases available. | ||
| */ | ||
| async getDatabases() { | ||
| return this.driver.getDatabases(); | ||
| } | ||
| /** | ||
| * Get the current database name. | ||
| */ | ||
| async getCurrentDatabase() { | ||
| return this.driver.getCurrentDatabase(); | ||
| } | ||
| /** | ||
| * Verify if database exists. | ||
| */ | ||
| async hasDatabase(database) { | ||
| return this.driver.hasDatabase(database); | ||
| } | ||
| /** | ||
| * Create a new database. | ||
| */ | ||
| async createDatabase(database) { | ||
| return this.driver.createDatabase(database); | ||
| } | ||
| /** | ||
| * Drop some database. | ||
| */ | ||
| async dropDatabase(database) { | ||
| return this.driver.dropDatabase(database); | ||
| } | ||
| /** | ||
| * List all tables available. | ||
| */ | ||
| async getTables() { | ||
| return this.driver.getTables(); | ||
| } | ||
| /** | ||
| * Verify if table exists. | ||
| */ | ||
| async hasTable(table) { | ||
| return this.driver.hasTable(table); | ||
| } | ||
| /** | ||
| * Create a new table in database. | ||
| */ | ||
| async createTable(table, closure) { | ||
| return this.driver.createTable(table, closure); | ||
| } | ||
| /** | ||
| * Alter a table in database. | ||
| */ | ||
| async alterTable(table, closure) { | ||
| return this.driver.alterTable(table, closure); | ||
| } | ||
| /** | ||
| * Drop a table in database. | ||
| */ | ||
| async dropTable(table) { | ||
| return this.driver.dropTable(table); | ||
| } | ||
| /** | ||
| * Remove all data inside some database table | ||
| * and restart the identity of the table. | ||
| */ | ||
| async truncate(table) { | ||
| return this.driver.truncate(table); | ||
| } | ||
| /** | ||
| * Make a raw query in database. | ||
| */ | ||
| raw(sql, bindings) { | ||
| return this.driver.raw(sql, bindings); | ||
| } | ||
| /** | ||
| * Creates a new instance of QueryBuilder for this table. | ||
| */ | ||
| table(table) { | ||
| return new QueryBuilder(this.driver, table); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export declare const debug: import("util").DebugLogger; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { debuglog } from 'node:util'; | ||
| export const debug = debuglog('athenna:database'); |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export declare class NotConnectedDatabaseException extends Exception { | ||
| constructor(); | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export class NotConnectedDatabaseException extends Exception { | ||
| constructor() { | ||
| const message = 'Database is not connected to perform queries.'; | ||
| super({ | ||
| message, | ||
| code: 'E_NOT_CONNECTED_ERROR', | ||
| help: `Remember to call "connect()" method before starting performing queries.` | ||
| }); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export declare class NotFoundDataException extends Exception { | ||
| constructor(con: string); | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export class NotFoundDataException extends Exception { | ||
| constructor(con) { | ||
| const message = 'Data not found in database.'; | ||
| super({ | ||
| message, | ||
| status: 404, | ||
| code: 'E_NOT_FOUND_DATA_ERROR', | ||
| help: `Data not found in database using the using ${con} connection.` | ||
| }); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export declare class NotFoundDriverException extends Exception { | ||
| constructor(driver: string); | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Path, Exception } from '@athenna/common'; | ||
| import { ConnectionFactory } from '#src/factories/ConnectionFactory'; | ||
| export class NotFoundDriverException extends Exception { | ||
| constructor(driver) { | ||
| const message = `The driver ${driver} has not been found.`; | ||
| const availableDrivers = ConnectionFactory.availableDrivers().join(', '); | ||
| super({ | ||
| message, | ||
| code: 'E_NOT_FOUND_DRIVER_ERROR', | ||
| help: `Available drivers are: ${availableDrivers}. Look into your config/database.${Path.ext()} file if ${driver} driver is implemented by database.` | ||
| }); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export declare class NotImplementedConfigException extends Exception { | ||
| constructor(con: string); | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Path, Exception, Is } from '@athenna/common'; | ||
| export class NotImplementedConfigException extends Exception { | ||
| constructor(con) { | ||
| let help = ''; | ||
| const connections = Config.get('database.connections'); | ||
| if (connections && !Is.Empty(connections)) { | ||
| const availableConfigs = Object.keys(connections).join(', '); | ||
| help += `Available configurations are: ${availableConfigs}.`; | ||
| } | ||
| else { | ||
| help += `The "Config.get('database.connections')" is empty, maybe your configuration files are not loaded?`; | ||
| } | ||
| help += ` Create your configuration inside connections object to use it. Or load your configuration files using "Config.safeLoad(Path.config('database.${Path.ext()}'))`; | ||
| super({ | ||
| status: 500, | ||
| code: 'E_NOT_IMPLEMENTED_CONFIG_ERROR', | ||
| message: `Connection ${con} is not configured inside database.connections object from config/database.${Path.ext()} file.`, | ||
| help | ||
| }); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export declare class NotImplementedMethodException extends Exception { | ||
| constructor(method: string, driver: string); | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export class NotImplementedMethodException extends Exception { | ||
| constructor(method, driver) { | ||
| super({ | ||
| status: 500, | ||
| code: 'E_NOT_IMPLEMENTED_METHOD_ERROR', | ||
| message: `The method ${method} is not available when using the ${driver} driver.`, | ||
| help: `Rely in the documentation to check how you could get the behavior of ${method} method working for your ${driver} driver. For example, when using mongo driver, it doesn't make sense to run the raw method since mongo queries are create from JS code` | ||
| }); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export declare class NotImplementedRelationException extends Exception { | ||
| constructor(relation: string, model: string, available: string); | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export class NotImplementedRelationException extends Exception { | ||
| constructor(relation, model, available) { | ||
| super({ | ||
| status: 500, | ||
| code: 'E_NOT_IMPLEMENTED_RELATION_ERROR', | ||
| message: `The relation ${relation} is not available in model ${model}.`, | ||
| help: `Available relations are: ${available}.` | ||
| }); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export declare class NullableValueException extends Exception { | ||
| constructor(records: any); | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export class NullableValueException extends Exception { | ||
| constructor(records) { | ||
| if (records.length > 1) { | ||
| records = records.join(', '); | ||
| } | ||
| else { | ||
| records = records[0]; | ||
| } | ||
| super({ | ||
| status: 400, | ||
| code: 'E_NULLABLE_VALUE_ERROR', | ||
| message: `The properties [${records}] are undefined or null.`, | ||
| help: `Your properties [${records}] has the option isNullable set to true in it's model. Try setting values to these properties or set the isNullable property to false.` | ||
| }); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export declare class UniqueValueException extends Exception { | ||
| constructor(records: Record<string, any>); | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export class UniqueValueException extends Exception { | ||
| constructor(records) { | ||
| let values = Object.values(records); | ||
| let properties = Object.keys(records); | ||
| if (properties.length > 1) { | ||
| values = values.join(', '); | ||
| properties = properties.join(', '); | ||
| } | ||
| else { | ||
| values = values[0]; | ||
| properties = properties[0]; | ||
| } | ||
| super({ | ||
| status: 400, | ||
| code: 'E_UNIQUE_VALUE_ERROR', | ||
| message: `The properties [${properties}] is unique in database and cannot be replicated.`, | ||
| help: `Your properties [${properties}] has the option isUnique set to true in it's model, meaning that the values [${values}] could not be used because there is another record with it in your database. Try creating your record with a different value, or set the isUnique property to false.` | ||
| }); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export declare class WrongMethodException extends Exception { | ||
| constructor(wrong: string, right: string); | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Exception } from '@athenna/common'; | ||
| export class WrongMethodException extends Exception { | ||
| constructor(wrong, right) { | ||
| const message = `The method ${wrong} should not be used to perform operations using this type of data.`; | ||
| super({ | ||
| message, | ||
| code: 'E_WRONG_METHOD_ERROR', | ||
| help: `Instead try using the ${right} method.` | ||
| }); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { DatabaseImpl } from '#src/database/DatabaseImpl'; | ||
| export declare const Database: import("@athenna/ioc").FacadeType<DatabaseImpl<any>>; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Facade } from '@athenna/ioc'; | ||
| import { DatabaseImpl } from '#src/database/DatabaseImpl'; | ||
| export const Database = Facade.createFor('Athenna/Core/Database'); |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { Driver } from '#src/database/drivers/Driver'; | ||
| import { FakeDriver } from '#src/database/drivers/FakeDriver'; | ||
| import { MongoDriver } from '#src/database/drivers/MongoDriver'; | ||
| import { MySqlDriver } from '#src/database/drivers/MySqlDriver'; | ||
| import { SqliteDriver } from '#src/database/drivers/SqliteDriver'; | ||
| import { PostgresDriver } from '#src/database/drivers/PostgresDriver'; | ||
| export declare class ConnectionFactory { | ||
| /** | ||
| * Holds all the open connections. | ||
| */ | ||
| static connections: Map<string, any>; | ||
| /** | ||
| * Holds all the Athenna drivers implementations available. | ||
| */ | ||
| static drivers: Map<string, any>; | ||
| static fabricate(con: 'fake'): typeof FakeDriver; | ||
| static fabricate(con: 'mongo'): MongoDriver; | ||
| static fabricate(con: 'mysql'): MySqlDriver; | ||
| static fabricate(con: 'sqlite'): SqliteDriver; | ||
| static fabricate(con: 'postgres'): PostgresDriver; | ||
| static fabricate(con: 'fake' | 'mongo' | 'mysql' | 'sqlite' | 'postgres' | string): typeof FakeDriver | MongoDriver | MySqlDriver | SqliteDriver | PostgresDriver; | ||
| /** | ||
| * Verify if client is present on a driver connection. | ||
| */ | ||
| static hasClient(con: string): boolean; | ||
| /** | ||
| * Get client of a connection. | ||
| */ | ||
| static getClient(con: string): any; | ||
| /** | ||
| * Set connection client on driver. | ||
| */ | ||
| static setClient(con: string, client: any): void; | ||
| /** | ||
| * Return all available drivers. | ||
| */ | ||
| static availableDrivers(): any[]; | ||
| /** | ||
| * Return all available connections. | ||
| */ | ||
| static availableConnections(): any[]; | ||
| /** | ||
| * Define your own database driver implementation to use | ||
| * within Database facade. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { Driver, ConnectionFactory } from '@athenna/database' | ||
| * | ||
| * class TestDriver extends Driver {} | ||
| * | ||
| * ConnectionFactory.createDriver('test', TestDriver) | ||
| * ``` | ||
| */ | ||
| static createDriver(name: string, impl: typeof Driver<any, any>): void; | ||
| /** | ||
| * Parse connection config name if is default | ||
| */ | ||
| private static parseConName; | ||
| /** | ||
| * Get the connection configuration of config/database file. | ||
| */ | ||
| private static getConnectionDriver; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { debug } from '#src/debug'; | ||
| import { FakeDriver } from '#src/database/drivers/FakeDriver'; | ||
| import { MongoDriver } from '#src/database/drivers/MongoDriver'; | ||
| import { MySqlDriver } from '#src/database/drivers/MySqlDriver'; | ||
| import { SqliteDriver } from '#src/database/drivers/SqliteDriver'; | ||
| import { PostgresDriver } from '#src/database/drivers/PostgresDriver'; | ||
| import { NotFoundDriverException } from '#src/exceptions/NotFoundDriverException'; | ||
| import { NotImplementedConfigException } from '#src/exceptions/NotImplementedConfigException'; | ||
| export class ConnectionFactory { | ||
| /** | ||
| * Holds all the open connections. | ||
| */ | ||
| static { this.connections = new Map(); } | ||
| /** | ||
| * Holds all the Athenna drivers implementations available. | ||
| */ | ||
| static { this.drivers = new Map() | ||
| .set('fake', { driver: FakeDriver }) | ||
| .set('mongo', { driver: MongoDriver }) | ||
| .set('mysql', { driver: MySqlDriver }) | ||
| .set('sqlite', { driver: SqliteDriver }) | ||
| .set('postgres', { driver: PostgresDriver }); } | ||
| /** | ||
| * Fabricate a new connection for a specific driver. | ||
| */ | ||
| static fabricate(con) { | ||
| con = this.parseConName(con); | ||
| const driverName = this.getConnectionDriver(con); | ||
| const Driver = this.drivers.get(driverName).driver; | ||
| const connection = this.connections.get(con); | ||
| if (!connection) { | ||
| this.connections.set(con, { client: null }); | ||
| return new Driver(con); | ||
| } | ||
| if (connection.client) { | ||
| debug('client found for connection %s using driver %s, using it as default', con, driverName); | ||
| return new Driver(con, connection.client); | ||
| } | ||
| return new Driver(con); | ||
| } | ||
| /** | ||
| * Verify if client is present on a driver connection. | ||
| */ | ||
| static hasClient(con) { | ||
| return !!this.connections.get(con)?.client; | ||
| } | ||
| /** | ||
| * Get client of a connection. | ||
| */ | ||
| static getClient(con) { | ||
| return this.connections.get(con)?.client; | ||
| } | ||
| /** | ||
| * Set connection client on driver. | ||
| */ | ||
| static setClient(con, client) { | ||
| const connection = this.connections.get(con) || {}; | ||
| connection.client = client; | ||
| this.connections.set(con, connection); | ||
| } | ||
| /** | ||
| * Return all available drivers. | ||
| */ | ||
| static availableDrivers() { | ||
| const availableDrivers = []; | ||
| for (const key of this.drivers.keys()) { | ||
| availableDrivers.push(key); | ||
| } | ||
| return availableDrivers; | ||
| } | ||
| /** | ||
| * Return all available connections. | ||
| */ | ||
| static availableConnections() { | ||
| const availableConnections = []; | ||
| for (const key of this.connections.keys()) { | ||
| availableConnections.push(key); | ||
| } | ||
| return availableConnections; | ||
| } | ||
| /** | ||
| * Define your own database driver implementation to use | ||
| * within Database facade. | ||
| * | ||
| * @example | ||
| * ```ts | ||
| * import { Driver, ConnectionFactory } from '@athenna/database' | ||
| * | ||
| * class TestDriver extends Driver {} | ||
| * | ||
| * ConnectionFactory.createDriver('test', TestDriver) | ||
| * ``` | ||
| */ | ||
| static createDriver(name, impl) { | ||
| this.drivers.set(name, { driver: impl }); | ||
| } | ||
| /** | ||
| * Parse connection config name if is default | ||
| */ | ||
| static parseConName(con) { | ||
| if (con === 'default') { | ||
| return Config.get('database.default'); | ||
| } | ||
| return con; | ||
| } | ||
| /** | ||
| * Get the connection configuration of config/database file. | ||
| */ | ||
| static getConnectionDriver(con) { | ||
| const config = Config.get(`database.connections.${con}`); | ||
| if (!config) { | ||
| throw new NotImplementedConfigException(con); | ||
| } | ||
| if (!this.drivers.has(config.driver)) { | ||
| throw new NotFoundDriverException(config.driver); | ||
| } | ||
| return config.driver; | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { RelationOptions, ColumnOptions, HasOneOptions, HasManyOptions, BelongsToOptions, BelongsToManyOptions } from '#src/types'; | ||
| export declare class Annotation { | ||
| static getColumnsMeta(target: any): ColumnOptions[]; | ||
| static defineColumnMeta(target: any, options: ColumnOptions): void; | ||
| static getRelationsMeta(target: any): RelationOptions[]; | ||
| static getHasOnesMeta(target: any): HasOneOptions[]; | ||
| static defineHasOneMeta(target: any, options: HasOneOptions): void; | ||
| static getHasManyMeta(target: any): HasManyOptions[]; | ||
| static defineHasManyMeta(target: any, options: HasManyOptions): void; | ||
| static getBelongsToMeta(target: any): BelongsToOptions[]; | ||
| static defineBelongsToMeta(target: any, options: BelongsToOptions): void; | ||
| static getBelongsToManyMeta(target: any): BelongsToManyOptions[]; | ||
| static defineBelongsToManyMeta(target: any, options: BelongsToManyOptions): void; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { COLUMNS_KEY, HAS_ONE_KEY, HAS_MANY_KEY, BELONGS_TO_KEY, BELONGS_TO_MANY_KEY } from '#src/constants/MetadataKeys'; | ||
| export class Annotation { | ||
| static getColumnsMeta(target) { | ||
| return Reflect.getMetadata(COLUMNS_KEY, target) || []; | ||
| } | ||
| static defineColumnMeta(target, options) { | ||
| const columns = Reflect.getMetadata(COLUMNS_KEY, target) || []; | ||
| columns.push(options); | ||
| Reflect.defineMetadata(COLUMNS_KEY, columns, target); | ||
| } | ||
| static getRelationsMeta(target) { | ||
| return [ | ||
| ...this.getHasOnesMeta(target), | ||
| ...this.getHasManyMeta(target), | ||
| ...this.getBelongsToMeta(target), | ||
| ...this.getBelongsToManyMeta(target) | ||
| ]; | ||
| } | ||
| static getHasOnesMeta(target) { | ||
| return Reflect.getMetadata(HAS_ONE_KEY, target) || []; | ||
| } | ||
| static defineHasOneMeta(target, options) { | ||
| const hasOne = Reflect.getMetadata(HAS_ONE_KEY, target) || []; | ||
| hasOne.push(options); | ||
| Reflect.defineMetadata(HAS_ONE_KEY, hasOne, target); | ||
| } | ||
| static getHasManyMeta(target) { | ||
| return Reflect.getMetadata(HAS_MANY_KEY, target) || []; | ||
| } | ||
| static defineHasManyMeta(target, options) { | ||
| const hasMany = Reflect.getMetadata(HAS_MANY_KEY, target) || []; | ||
| hasMany.push(options); | ||
| Reflect.defineMetadata(HAS_MANY_KEY, hasMany, target); | ||
| } | ||
| static getBelongsToMeta(target) { | ||
| return Reflect.getMetadata(BELONGS_TO_KEY, target) || []; | ||
| } | ||
| static defineBelongsToMeta(target, options) { | ||
| const belongsTo = Reflect.getMetadata(BELONGS_TO_KEY, target) || []; | ||
| belongsTo.push(options); | ||
| Reflect.defineMetadata(BELONGS_TO_KEY, belongsTo, target); | ||
| } | ||
| static getBelongsToManyMeta(target) { | ||
| return Reflect.getMetadata(BELONGS_TO_MANY_KEY, target) || []; | ||
| } | ||
| static defineBelongsToManyMeta(target, options) { | ||
| const belongsToMany = Reflect.getMetadata(BELONGS_TO_MANY_KEY, target) || []; | ||
| belongsToMany.push(options); | ||
| Reflect.defineMetadata(BELONGS_TO_MANY_KEY, belongsToMany, target); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export declare class ObjectId { | ||
| /** | ||
| * Validate if is a valid object id. | ||
| */ | ||
| static isValid(objectId: any): boolean; | ||
| /** | ||
| * Validate if is a valid object id string or ObjectID object. | ||
| */ | ||
| static isValidStringOrObject(objectId: any): boolean; | ||
| /** | ||
| * Validate if is a valid object id string. | ||
| */ | ||
| static isValidString(objectId: any): boolean; | ||
| /** | ||
| * Swap the value for an objectId instance if valid. | ||
| * If not valid, return the value. | ||
| */ | ||
| static ifValidSwap(value: any): any; | ||
| /** | ||
| * Validate if is a valid object id object. | ||
| */ | ||
| static isValidObject(objectId: any): boolean; | ||
| constructor(value: any); | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Is, Module } from '@athenna/common'; | ||
| const mongoose = await Module.safeImport('mongoose'); | ||
| export class ObjectId { | ||
| /** | ||
| * Validate if is a valid object id. | ||
| */ | ||
| static isValid(objectId) { | ||
| if (!mongoose) { | ||
| return false; | ||
| } | ||
| // eslint-disable-next-line | ||
| return mongoose.isValidObjectId(objectId) && new mongoose.Types.ObjectId(objectId) == objectId; | ||
| } | ||
| /** | ||
| * Validate if is a valid object id string or ObjectID object. | ||
| */ | ||
| static isValidStringOrObject(objectId) { | ||
| return this.isValidString(objectId) || this.isValidObject(objectId); | ||
| } | ||
| /** | ||
| * Validate if is a valid object id string. | ||
| */ | ||
| static isValidString(objectId) { | ||
| if (!mongoose) { | ||
| return false; | ||
| } | ||
| return Is.String(objectId) && this.isValid(objectId); | ||
| } | ||
| /** | ||
| * Swap the value for an objectId instance if valid. | ||
| * If not valid, return the value. | ||
| */ | ||
| static ifValidSwap(value) { | ||
| if (ObjectId.isValidString(value)) { | ||
| return new ObjectId(value); | ||
| } | ||
| return value; | ||
| } | ||
| /** | ||
| * Validate if is a valid object id object. | ||
| */ | ||
| static isValidObject(objectId) { | ||
| if (!mongoose) { | ||
| return false; | ||
| } | ||
| return (!Is.Number(objectId) && | ||
| !Is.String(objectId) && | ||
| mongoose.isValidObjectId(objectId)); | ||
| } | ||
| constructor(value) { | ||
| return new mongoose.Types.ObjectId(value); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export * from '#src/types'; | ||
| export * from '#src/models/BaseModel'; | ||
| export * from '#src/models/builders/ModelQueryBuilder'; | ||
| export * from '#src/models/schemas/ModelSchema'; | ||
| export * from '#src/models/annotations/Column'; | ||
| export * from '#src/models/annotations/HasOne'; | ||
| export * from '#src/models/annotations/HasMany'; | ||
| export * from '#src/models/annotations/BelongsTo'; | ||
| export * from '#src/models/annotations/BelongsToMany'; | ||
| export * from '#src/database/DatabaseImpl'; | ||
| export * from '#src/database/seeders/BaseSeeder'; | ||
| export * from '#src/database/migrations/BaseMigration'; | ||
| export * from '#src/database/builders/QueryBuilder'; | ||
| export * from '#src/database/transactions/Transaction'; | ||
| export * from '#src/database/migrations/MigrationSource'; | ||
| export * from '#src/database/drivers/Driver'; | ||
| export * from '#src/factories/ConnectionFactory'; | ||
| export * from '#src/helpers/Annotation'; | ||
| export * from '#src/helpers/ObjectId'; | ||
| export * from '#src/facades/Database'; | ||
| export * from '#src/providers/DatabaseProvider'; |
+29
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export * from '#src/types'; | ||
| export * from '#src/models/BaseModel'; | ||
| export * from '#src/models/builders/ModelQueryBuilder'; | ||
| export * from '#src/models/schemas/ModelSchema'; | ||
| export * from '#src/models/annotations/Column'; | ||
| export * from '#src/models/annotations/HasOne'; | ||
| export * from '#src/models/annotations/HasMany'; | ||
| export * from '#src/models/annotations/BelongsTo'; | ||
| export * from '#src/models/annotations/BelongsToMany'; | ||
| export * from '#src/database/DatabaseImpl'; | ||
| export * from '#src/database/seeders/BaseSeeder'; | ||
| export * from '#src/database/migrations/BaseMigration'; | ||
| export * from '#src/database/builders/QueryBuilder'; | ||
| export * from '#src/database/transactions/Transaction'; | ||
| export * from '#src/database/migrations/MigrationSource'; | ||
| export * from '#src/database/drivers/Driver'; | ||
| export * from '#src/factories/ConnectionFactory'; | ||
| export * from '#src/helpers/Annotation'; | ||
| export * from '#src/helpers/ObjectId'; | ||
| export * from '#src/facades/Database'; | ||
| export * from '#src/providers/DatabaseProvider'; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { BelongsToOptions } from '#src/types/relations/BelongsToOptions'; | ||
| /** | ||
| * Create belongs to relation for model class. | ||
| */ | ||
| export declare function BelongsTo<T extends BaseModel = any, R extends BaseModel = any>(model: (() => new () => R) | string, options?: Omit<BelongsToOptions<T, R>, 'type' | 'model' | 'property'>): (target: T, key: any) => void; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import { debug } from '#src/debug'; | ||
| import { Is, Options } from '@athenna/common'; | ||
| import { Annotation } from '#src/helpers/Annotation'; | ||
| /** | ||
| * Create belongs to relation for model class. | ||
| */ | ||
| export function BelongsTo(model, options = {}) { | ||
| return (target, key) => { | ||
| const Target = target.constructor; | ||
| options = Options.create(options, { | ||
| isIncluded: false, | ||
| // Default will be set later as: RelationModel.schema().getMainPrimaryKeyProperty() | ||
| primaryKey: undefined, | ||
| // Default will be set later as: `${String.toCamelCase(RelationModel.name)}Id` | ||
| foreignKey: undefined | ||
| }); | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.type = 'belongsTo'; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.model = Is.String(model) | ||
| ? () => ioc.safeUse(`App/Models/${model}`).constructor | ||
| : model; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.property = key; | ||
| debug('registering belongsTo metadata for model %s: %o', Target.name, options); | ||
| Annotation.defineBelongsToMeta(Target, options); | ||
| }; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { BelongsToManyOptions } from '#src/types/relations/BelongsToManyOptions'; | ||
| /** | ||
| * Create belongs to many relation for model class. | ||
| */ | ||
| export declare function BelongsToMany<T extends BaseModel = any, R extends BaseModel = any, P extends BaseModel = any>(model: (() => new () => R) | string, pivotModel: (() => new () => P) | string, options?: Omit<BelongsToManyOptions<T, R, P>, 'type' | 'model' | 'property'>): (target: T, key: any) => void; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import { debug } from '#src/debug'; | ||
| import { Annotation } from '#src/helpers/Annotation'; | ||
| import { Is, Options, String } from '@athenna/common'; | ||
| /** | ||
| * Create belongs to many relation for model class. | ||
| */ | ||
| export function BelongsToMany(model, pivotModel, options = {}) { | ||
| return (target, key) => { | ||
| const Target = target.constructor; | ||
| options = Options.create(options, { | ||
| isIncluded: false, | ||
| primaryKey: Target.schema().getMainPrimaryKeyName(), | ||
| foreignKey: `${String.toCamelCase(Target.name)}Id`, | ||
| // Default value will be set later as: `${Model.table()}_${RelationModel.table()}` | ||
| pivotTable: undefined, | ||
| // Default value will be set later as: Relation.schema().getMainPrimaryKeyName() | ||
| relationPrimaryKey: undefined, | ||
| // Default value will be set later as: `${String.toCamelCase(Relation.name)}Id` | ||
| relationForeignKey: undefined | ||
| }); | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.type = 'belongsToMany'; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.model = Is.String(model) | ||
| ? () => ioc.safeUse(`App/Models/${model}`).constructor | ||
| : model; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.pivotModel = Is.String(pivotModel) | ||
| ? () => ioc.safeUse(`App/Models/${pivotModel}`).constructor | ||
| : pivotModel; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.property = key; | ||
| debug('registering belongsToMany metadata for model %s: %o', Target.name, options); | ||
| Annotation.defineBelongsToManyMeta(Target, options); | ||
| }; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import type { ColumnOptions } from '#src/types/columns/ColumnOptions'; | ||
| /** | ||
| * Create column for model class. | ||
| */ | ||
| export declare function Column(options?: Omit<ColumnOptions, 'property' | 'hasSetName'>): PropertyDecorator; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import { debug } from '#src/debug'; | ||
| import { Options } from '@athenna/common'; | ||
| import { Annotation } from '#src/helpers/Annotation'; | ||
| /** | ||
| * Create column for model class. | ||
| */ | ||
| export function Column(options = {}) { | ||
| return (target, key) => { | ||
| const hasSetName = !!options.name; | ||
| options = Options.create(options, { | ||
| name: key, | ||
| type: Reflect.getMetadata('design:type', target, key), | ||
| defaultTo: null, | ||
| isPrimary: false, | ||
| isHidden: false, | ||
| isUnique: false, | ||
| isNullable: true, | ||
| isIndex: false, | ||
| isSparse: false, | ||
| persist: true, | ||
| isMainPrimary: false, | ||
| isCreateDate: false, | ||
| isUpdateDate: false, | ||
| isDeleteDate: false | ||
| }); | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.property = key; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.hasSetName = hasSetName; | ||
| if (options.isMainPrimary) { | ||
| options.isPrimary = true; | ||
| } | ||
| const Target = target.constructor; | ||
| debug('registering column metadata for model %s: %o', Target.name, options); | ||
| Annotation.defineColumnMeta(Target, options); | ||
| }; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { HasManyOptions } from '#src/types/relations/HasManyOptions'; | ||
| /** | ||
| * Create has many relation for model class. | ||
| */ | ||
| export declare function HasMany<T extends BaseModel = any, R extends BaseModel = any>(model: (() => new () => R) | string, options?: Omit<HasManyOptions, 'type' | 'model' | 'property'>): (target: T, key: any) => void; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import { debug } from '#src/debug'; | ||
| import { Annotation } from '#src/helpers/Annotation'; | ||
| import { Is, Options, String } from '@athenna/common'; | ||
| /** | ||
| * Create has many relation for model class. | ||
| */ | ||
| export function HasMany(model, options = {}) { | ||
| return (target, key) => { | ||
| const Target = target.constructor; | ||
| options = Options.create(options, { | ||
| isIncluded: false, | ||
| primaryKey: Target.schema().getMainPrimaryKeyProperty(), | ||
| foreignKey: `${String.toCamelCase(Target.name)}Id` | ||
| }); | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.type = 'hasMany'; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.model = Is.String(model) | ||
| ? () => ioc.safeUse(`App/Models/${model}`).constructor | ||
| : model; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.property = key; | ||
| debug('registering hasMany metadata for model %s: %o', Target.name, options); | ||
| Annotation.defineHasManyMeta(Target, options); | ||
| }; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { HasOneOptions } from '#src/types/relations/HasOneOptions'; | ||
| /** | ||
| * Create has one relation for model class. | ||
| */ | ||
| export declare function HasOne<T extends BaseModel = any, R extends BaseModel = any>(model: (() => new () => R) | string, options?: Omit<HasOneOptions<T, R>, 'type' | 'model' | 'property'>): (target: T, key: string) => void; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import 'reflect-metadata'; | ||
| import { debug } from '#src/debug'; | ||
| import { Annotation } from '#src/helpers/Annotation'; | ||
| import { Is, Options, String } from '@athenna/common'; | ||
| /** | ||
| * Create has one relation for model class. | ||
| */ | ||
| export function HasOne(model, options = {}) { | ||
| return (target, key) => { | ||
| const Target = target.constructor; | ||
| options = Options.create(options, { | ||
| isIncluded: false, | ||
| primaryKey: Target.schema().getMainPrimaryKeyProperty(), | ||
| foreignKey: `${String.toCamelCase(Target.name)}Id` | ||
| }); | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.type = 'hasOne'; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.model = Is.String(model) | ||
| ? () => ioc.safeUse(`App/Models/${model}`).constructor | ||
| : model; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| options.property = key; | ||
| debug('registering hasOne metadata for model %s: %o', Target.name, options); | ||
| Annotation.defineHasOneMeta(Target, options); | ||
| }; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Collection, type PaginatedResponse, type PaginationOptions } from '@athenna/common'; | ||
| import type { ModelRelations } from '#src/types'; | ||
| import { type Faker } from '@faker-js/faker'; | ||
| import { ModelSchema } from '#src/models/schemas/ModelSchema'; | ||
| import { ORIGINAL_SYMBOL } from '#src/constants/OriginalSymbol'; | ||
| import { ModelFactory } from '#src/models/factories/ModelFactory'; | ||
| import { ModelQueryBuilder } from '#src/models/builders/ModelQueryBuilder'; | ||
| export declare class BaseModel { | ||
| /** | ||
| * Set if the `attributes` method should be called or not. | ||
| */ | ||
| private static get isToSetAttributes(); | ||
| /** | ||
| * Set if the option annotation `isUnique` | ||
| * should be verified or not. | ||
| */ | ||
| private static get isToValidateUnique(); | ||
| /** | ||
| * Set if the option annotation `isNullable` | ||
| * should be verified or not. | ||
| */ | ||
| private static get isToValidateNullable(); | ||
| /** | ||
| * The faker instance to create fake data in | ||
| * definition instance. | ||
| */ | ||
| static get faker(): Faker; | ||
| /** | ||
| * Set the connection name that model will use | ||
| * to access database. | ||
| */ | ||
| static connection(): any; | ||
| /** | ||
| * Set if model should automatically be sync with | ||
| * database when running DatabaseProvider. | ||
| * | ||
| * @default true | ||
| */ | ||
| static sync(): boolean; | ||
| /** | ||
| * Set the table name of this model instance. | ||
| */ | ||
| static table(): string; | ||
| /** | ||
| * Set the default values that should be set when creating or | ||
| * updating the model. | ||
| */ | ||
| static attributes(): Record<string, unknown>; | ||
| /** | ||
| * Set the definition data that will be used when fabricating | ||
| * instances of your model using factories. | ||
| */ | ||
| static definition(): Promise<Record<string, unknown>>; | ||
| /** | ||
| * Create a new ModelSchema instance from your model. | ||
| */ | ||
| static schema<T extends typeof BaseModel>(this: T): ModelSchema<InstanceType<T>>; | ||
| /** | ||
| * Create a new ModelFactory instance from your model. | ||
| */ | ||
| static factory<T extends typeof BaseModel>(this: T): ModelFactory<InstanceType<T>, InstanceType<T>>; | ||
| /** | ||
| * Enable/disable setting the default attributes properties | ||
| * when creating/updating models. | ||
| */ | ||
| static setAttributes<T extends typeof BaseModel>(this: T, value: boolean): T; | ||
| /** | ||
| * Enable/disable the `isUnique` property validation of | ||
| * models columns. | ||
| */ | ||
| static uniqueValidation<T extends typeof BaseModel>(this: T, value: boolean): T; | ||
| /** | ||
| * Enable/disable the `isNullable` property validation of | ||
| * models columns. | ||
| */ | ||
| static nullableValidation<T extends typeof BaseModel>(this: T, value: boolean): T; | ||
| /** | ||
| * Create a query builder for the model. | ||
| */ | ||
| static query<T extends typeof BaseModel>(this: T): ModelQueryBuilder<InstanceType<T>, import("../database/drivers/MongoDriver.js").MongoDriver>; | ||
| /** | ||
| * Remove all data inside model table | ||
| * and restart the identity of the table. | ||
| */ | ||
| static truncate(): Promise<void>; | ||
| /** | ||
| * Find value in database but returns only the value of | ||
| * selected column directly. | ||
| */ | ||
| static pluck<T extends typeof BaseModel, K extends keyof InstanceType<T> = keyof InstanceType<T>>(this: T, key: K, where?: Partial<InstanceType<T>>): Promise<InstanceType<T>[K]>; | ||
| /** | ||
| * Find many values in database but returns only the | ||
| * values of selected column directly. | ||
| */ | ||
| static pluckMany<T extends typeof BaseModel, K extends keyof InstanceType<T> = keyof InstanceType<T>>(this: T, key: K, where?: Partial<InstanceType<T>>): Promise<InstanceType<T>[K][]>; | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| static find<T extends typeof BaseModel>(this: T, where?: Partial<InstanceType<T>>): Promise<InstanceType<T>>; | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| static exists<T extends typeof BaseModel>(this: T, where?: Partial<InstanceType<T>>): Promise<boolean>; | ||
| /** | ||
| * Find a value in database or throw exception if undefined. | ||
| */ | ||
| static findOrFail<T extends typeof BaseModel>(this: T, where?: Partial<InstanceType<T>>): Promise<InstanceType<T>>; | ||
| /** | ||
| * Return a single data or, if no results are found, | ||
| * execute the given closure. | ||
| */ | ||
| static findOr<T extends typeof BaseModel>(this: T, where: Partial<InstanceType<T>>, closure: () => any | Promise<any>): Promise<InstanceType<T> | any>; | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| static findMany<T extends typeof BaseModel>(this: T, where?: Partial<InstanceType<T>>): Promise<InstanceType<T>[]>; | ||
| /** | ||
| * Find many values in database and return paginated. | ||
| */ | ||
| static paginate<T extends typeof BaseModel>(this: T, options?: PaginationOptions, where?: Partial<InstanceType<T>>): Promise<PaginatedResponse<InstanceType<T>>>; | ||
| /** | ||
| * Find many values in database and return | ||
| * as a collection instance. | ||
| */ | ||
| static collection<T extends typeof BaseModel>(this: T, where?: Partial<InstanceType<T>>): Promise<Collection<InstanceType<T>>>; | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| static create<T extends typeof BaseModel>(this: T, data?: Partial<InstanceType<T>>, cleanPersist?: boolean): Promise<InstanceType<T>>; | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| static createMany<T extends typeof BaseModel>(this: T, data: Partial<InstanceType<T>>[], cleanPersist?: boolean): Promise<InstanceType<T>[]>; | ||
| /** | ||
| * Create or update a value in database. | ||
| */ | ||
| static createOrUpdate<T extends typeof BaseModel>(this: T, where: Partial<InstanceType<T>>, data: Partial<InstanceType<T>>, cleanPersist?: boolean): Promise<InstanceType<T> | InstanceType<T>[]>; | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| static update<T extends typeof BaseModel>(this: T, where: Partial<InstanceType<T>>, data: Partial<InstanceType<T>>, cleanPersist?: boolean): Promise<InstanceType<T> | InstanceType<T>[]>; | ||
| /** | ||
| * Delete or soft delete a value in database. | ||
| */ | ||
| static delete<T extends typeof BaseModel>(this: T, where: Partial<InstanceType<T>>, force?: boolean): Promise<void>; | ||
| /** | ||
| * The original model values when it was fetched | ||
| * from database. If is undefined, means that model | ||
| * is a fresh instance and is not available in database | ||
| * yet. | ||
| */ | ||
| private [ORIGINAL_SYMBOL]?; | ||
| /** | ||
| * Set the original model values by deep copying | ||
| * the model state. | ||
| */ | ||
| setOriginal(): this; | ||
| /** | ||
| * Return a Json object from the actual subclass instance. | ||
| */ | ||
| toJSON(options?: { | ||
| withHidden?: boolean; | ||
| }): Record<string, any>; | ||
| load(relation: string): Promise<any>; | ||
| load<K extends ModelRelations<this>>(relation: K, closure?: (query: ModelQueryBuilder<Extract<this[K] extends BaseModel[] ? this[K][0] : this[K], BaseModel>>) => any): Promise<this[K]>; | ||
| /** | ||
| * Validate if model is persisted in database | ||
| * or if it's a fresh instance. | ||
| */ | ||
| isPersisted(): boolean; | ||
| /** | ||
| * Get values only that are different from | ||
| * the original symbol to avoid updating | ||
| * data that was not changed. | ||
| */ | ||
| dirty(): this | Record<string, any>; | ||
| /** | ||
| * Validate if model has been changed from | ||
| * it initial state when it was retrieved from | ||
| * database. | ||
| */ | ||
| isDirty(): boolean; | ||
| /** | ||
| * Save the changes done in the model in database. | ||
| */ | ||
| save(cleanPersist?: boolean): Promise<this>; | ||
| /** | ||
| * Create a new instance of the model from retrieving | ||
| * again the data from database. The existing | ||
| * model instance WILL NOT BE affected. | ||
| */ | ||
| fresh(): Promise<any>; | ||
| /** | ||
| * Refresh the model instance data retrieving | ||
| * model data using the main primary key. The | ||
| * existing model instance WILL BE affected. | ||
| */ | ||
| refresh(): Promise<void>; | ||
| /** | ||
| * Verify if model is soft deleted. | ||
| */ | ||
| isTrashed(): boolean; | ||
| /** | ||
| * Delete or soft delete your model from database. | ||
| */ | ||
| delete(force?: boolean): Promise<void>; | ||
| /** | ||
| * Restore a soft deleted model from database. | ||
| */ | ||
| restore(): Promise<this>; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Is, Json, String, Options, Collection } from '@athenna/common'; | ||
| import { Database } from '#src/facades/Database'; | ||
| import { faker } from '@faker-js/faker'; | ||
| import { ModelSchema } from '#src/models/schemas/ModelSchema'; | ||
| import { ORIGINAL_SYMBOL } from '#src/constants/OriginalSymbol'; | ||
| import { ModelFactory } from '#src/models/factories/ModelFactory'; | ||
| import { ModelGenerator } from '#src/models/factories/ModelGenerator'; | ||
| import { ModelQueryBuilder } from '#src/models/builders/ModelQueryBuilder'; | ||
| export class BaseModel { | ||
| /** | ||
| * Set if the `attributes` method should be called or not. | ||
| */ | ||
| static get isToSetAttributes() { | ||
| return Config.get(`database.connections.${this.connection()}.validations.isToSetAttributes`, true); | ||
| } | ||
| /** | ||
| * Set if the option annotation `isUnique` | ||
| * should be verified or not. | ||
| */ | ||
| static get isToValidateUnique() { | ||
| return Config.get(`database.connections.${this.connection()}.validations.isToValidateUnique`, true); | ||
| } | ||
| /** | ||
| * Set if the option annotation `isNullable` | ||
| * should be verified or not. | ||
| */ | ||
| static get isToValidateNullable() { | ||
| return Config.get(`database.connections.${this.connection()}.validations.isToValidateNullable`, true); | ||
| } | ||
| /** | ||
| * The faker instance to create fake data in | ||
| * definition instance. | ||
| */ | ||
| static get faker() { | ||
| return faker; | ||
| } | ||
| /** | ||
| * Set the connection name that model will use | ||
| * to access database. | ||
| */ | ||
| static connection() { | ||
| return Config.get('database.default'); | ||
| } | ||
| /** | ||
| * Set if model should automatically be sync with | ||
| * database when running DatabaseProvider. | ||
| * | ||
| * @default true | ||
| */ | ||
| static sync() { | ||
| const connection = this.connection(); | ||
| const driver = Config.get(`database.connections.${connection}.driver`); | ||
| if (driver === 'mongo') { | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| /** | ||
| * Set the table name of this model instance. | ||
| */ | ||
| static table() { | ||
| return String.pluralize(String.toSnakeCase(this.name).toLowerCase()); | ||
| } | ||
| /** | ||
| * Set the default values that should be set when creating or | ||
| * updating the model. | ||
| */ | ||
| static attributes() { | ||
| return {}; | ||
| } | ||
| /** | ||
| * Set the definition data that will be used when fabricating | ||
| * instances of your model using factories. | ||
| */ | ||
| static async definition() { | ||
| return {}; | ||
| } | ||
| /** | ||
| * Create a new ModelSchema instance from your model. | ||
| */ | ||
| static schema() { | ||
| return new ModelSchema(this); | ||
| } | ||
| /** | ||
| * Create a new ModelFactory instance from your model. | ||
| */ | ||
| static factory() { | ||
| return new ModelFactory(this); | ||
| } | ||
| /** | ||
| * Enable/disable setting the default attributes properties | ||
| * when creating/updating models. | ||
| */ | ||
| static setAttributes(value) { | ||
| Config.set(`database.connections.${this.connection()}.validations.isToSetAttributes`, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Enable/disable the `isUnique` property validation of | ||
| * models columns. | ||
| */ | ||
| static uniqueValidation(value) { | ||
| Config.set(`database.connections.${this.connection()}.validations.isToValidateUnique`, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Enable/disable the `isNullable` property validation of | ||
| * models columns. | ||
| */ | ||
| static nullableValidation(value) { | ||
| Config.set(`database.connections.${this.connection()}.validations.isToValidateNullable`, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Create a query builder for the model. | ||
| */ | ||
| static query() { | ||
| const driver = Database.connection(this.connection()).driver; | ||
| return new ModelQueryBuilder(this, driver) | ||
| .setAttributes(this.isToSetAttributes) | ||
| .uniqueValidation(this.isToValidateUnique) | ||
| .nullableValidation(this.isToValidateNullable); | ||
| } | ||
| /** | ||
| * Remove all data inside model table | ||
| * and restart the identity of the table. | ||
| */ | ||
| static async truncate() { | ||
| await Database.connection(this.connection()).truncate(this.table()); | ||
| } | ||
| /** | ||
| * Find value in database but returns only the value of | ||
| * selected column directly. | ||
| */ | ||
| static async pluck(key, where) { | ||
| const query = this.query(); | ||
| if (where) { | ||
| query.where(where); | ||
| } | ||
| return query.pluck(key); | ||
| } | ||
| /** | ||
| * Find many values in database but returns only the | ||
| * values of selected column directly. | ||
| */ | ||
| static async pluckMany(key, where) { | ||
| const query = this.query(); | ||
| if (where) { | ||
| query.where(where); | ||
| } | ||
| return query.pluckMany(key); | ||
| } | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| static async find(where) { | ||
| const query = this.query(); | ||
| if (where) { | ||
| query.where(where); | ||
| } | ||
| return query.find(); | ||
| } | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| static async exists(where) { | ||
| const query = this.query(); | ||
| if (where) { | ||
| query.where(where); | ||
| } | ||
| return query.exists(); | ||
| } | ||
| /** | ||
| * Find a value in database or throw exception if undefined. | ||
| */ | ||
| static async findOrFail(where) { | ||
| const query = this.query(); | ||
| if (where) { | ||
| query.where(where); | ||
| } | ||
| return query.findOrFail(); | ||
| } | ||
| /** | ||
| * Return a single data or, if no results are found, | ||
| * execute the given closure. | ||
| */ | ||
| static async findOr(where, closure) { | ||
| const query = this.query(); | ||
| if (where) { | ||
| query.where(where); | ||
| } | ||
| return query.findOr(closure); | ||
| } | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| static async findMany(where) { | ||
| const query = this.query(); | ||
| if (where) { | ||
| query.where(where); | ||
| } | ||
| return query.findMany(); | ||
| } | ||
| /** | ||
| * Find many values in database and return paginated. | ||
| */ | ||
| static async paginate(options, where) { | ||
| const query = this.query(); | ||
| if (where) { | ||
| query.where(where); | ||
| } | ||
| return query.paginate(options); | ||
| } | ||
| /** | ||
| * Find many values in database and return | ||
| * as a collection instance. | ||
| */ | ||
| static async collection(where) { | ||
| const query = this.query(); | ||
| if (where) { | ||
| query.where(where); | ||
| } | ||
| return query.collection(); | ||
| } | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| static async create(data = {}, cleanPersist = true) { | ||
| return this.query().create(data, cleanPersist); | ||
| } | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| static async createMany(data, cleanPersist = true) { | ||
| return this.query().createMany(data, cleanPersist); | ||
| } | ||
| /** | ||
| * Create or update a value in database. | ||
| */ | ||
| static async createOrUpdate(where, data, cleanPersist = true) { | ||
| const query = this.query(); | ||
| if (where) { | ||
| query.where(where); | ||
| } | ||
| return query.createOrUpdate(data, cleanPersist); | ||
| } | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| static async update(where, data, cleanPersist = true) { | ||
| const query = this.query(); | ||
| if (where) { | ||
| query.where(where); | ||
| } | ||
| return query.update(data, cleanPersist); | ||
| } | ||
| /** | ||
| * Delete or soft delete a value in database. | ||
| */ | ||
| static async delete(where, force = false) { | ||
| const query = this.query(); | ||
| if (where) { | ||
| query.where(where); | ||
| } | ||
| return query.delete(force); | ||
| } | ||
| /** | ||
| * Set the original model values by deep copying | ||
| * the model state. | ||
| */ | ||
| setOriginal() { | ||
| this[ORIGINAL_SYMBOL] = {}; | ||
| Object.keys(Json.copy(this)).forEach(key => { | ||
| const value = this[key]; | ||
| if (Is.Array(value) && value[0] && ORIGINAL_SYMBOL in value[0]) { | ||
| return; | ||
| } | ||
| if (Is.Object(value) && value && ORIGINAL_SYMBOL in value) { | ||
| return; | ||
| } | ||
| this[ORIGINAL_SYMBOL][key] = value; | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Return a Json object from the actual subclass instance. | ||
| */ | ||
| toJSON(options) { | ||
| options = Options.create(options, { | ||
| withHidden: false | ||
| }); | ||
| const _Model = this.constructor; | ||
| const json = {}; | ||
| const relations = _Model.schema().getRelationProperties(); | ||
| /** | ||
| * Execute the toJSON of relations. | ||
| */ | ||
| Object.keys(this).forEach(key => { | ||
| if (relations.includes(key)) { | ||
| if (Is.Array(this[key])) { | ||
| json[key] = this[key].map(d => (d.toJSON ? d.toJSON() : d)); | ||
| return; | ||
| } | ||
| json[key] = this[key]?.toJSON ? this[key].toJSON() : this[key]; | ||
| return; | ||
| } | ||
| if (!options.withHidden && | ||
| _Model.schema().getColumnByProperty(key)?.isHidden) { | ||
| return; | ||
| } | ||
| json[key] = this[key]; | ||
| }); | ||
| return json; | ||
| } | ||
| /** | ||
| * Eager load a model relation from model instance. | ||
| */ | ||
| async load(relation, closure) { | ||
| const Model = this.constructor; | ||
| const schema = Model.schema(); | ||
| const generator = new ModelGenerator(Model, schema); | ||
| await generator.includeRelation(this, schema.includeRelation(relation, closure)); | ||
| if (relation.includes('.')) { | ||
| return Json.get(this, relation); | ||
| } | ||
| return this[relation]; | ||
| } | ||
| /** | ||
| * Validate if model is persisted in database | ||
| * or if it's a fresh instance. | ||
| */ | ||
| isPersisted() { | ||
| return !!this[ORIGINAL_SYMBOL]; | ||
| } | ||
| /** | ||
| * Get values only that are different from | ||
| * the original symbol to avoid updating | ||
| * data that was not changed. | ||
| */ | ||
| dirty() { | ||
| if (!this.isPersisted()) { | ||
| return this; | ||
| } | ||
| const dirty = {}; | ||
| Object.keys(this).forEach(key => { | ||
| const orig = this[ORIGINAL_SYMBOL][key]; | ||
| const curr = this[key]; | ||
| if (Json.isEqual(orig, curr)) { | ||
| return; | ||
| } | ||
| if (Is.Object(curr) || Is.Array(curr)) { | ||
| dirty[key] = Json.copy(curr); | ||
| return; | ||
| } | ||
| dirty[key] = Json.diff(orig, curr); | ||
| }); | ||
| return dirty; | ||
| } | ||
| /** | ||
| * Validate if model has been changed from | ||
| * it initial state when it was retrieved from | ||
| * database. | ||
| */ | ||
| isDirty() { | ||
| return Object.keys(this.dirty()).length > 0; | ||
| } | ||
| /** | ||
| * Save the changes done in the model in database. | ||
| */ | ||
| async save(cleanPersist = true) { | ||
| const Model = this.constructor; | ||
| const schema = Model.schema(); | ||
| const primaryKey = schema.getMainPrimaryKeyProperty(); | ||
| const date = new Date(); | ||
| const createdAt = schema.getCreatedAtColumn(); | ||
| const updatedAt = schema.getUpdatedAtColumn(); | ||
| const deletedAt = schema.getDeletedAtColumn(); | ||
| const attributes = Model.isToSetAttributes ? Model.attributes() : {}; | ||
| Object.keys(attributes).forEach(key => { | ||
| if (this[key]) { | ||
| return; | ||
| } | ||
| this[key] = attributes[key]; | ||
| }); | ||
| if (createdAt && this[createdAt.property] === undefined) { | ||
| this[createdAt.property] = date; | ||
| } | ||
| if (updatedAt && this[updatedAt.property] === undefined) { | ||
| this[updatedAt.property] = date; | ||
| } | ||
| if (deletedAt && this[deletedAt.property] === undefined) { | ||
| this[deletedAt.property] = null; | ||
| } | ||
| const data = this.dirty(); | ||
| if (!this.isPersisted()) { | ||
| const created = await Model.create(data, cleanPersist); | ||
| Object.keys(created).forEach(key => (this[key] = created[key])); | ||
| return this.setOriginal(); | ||
| } | ||
| /** | ||
| * Means data is not dirty because there are any | ||
| * value that is different from original symbol. | ||
| */ | ||
| if (!Object.keys(data).length) { | ||
| return this; | ||
| } | ||
| const where = { [primaryKey]: this[primaryKey] }; | ||
| const updated = await Model.update(where, data, cleanPersist); | ||
| Object.keys(updated).forEach(key => (this[key] = updated[key])); | ||
| return this.setOriginal(); | ||
| } | ||
| /** | ||
| * Create a new instance of the model from retrieving | ||
| * again the data from database. The existing | ||
| * model instance WILL NOT BE affected. | ||
| */ | ||
| async fresh() { | ||
| const Model = this.constructor; | ||
| const primaryKey = Model.schema().getMainPrimaryKeyProperty(); | ||
| return Model.query() | ||
| .where(primaryKey, this[primaryKey]) | ||
| .withTrashed() | ||
| .find(); | ||
| } | ||
| /** | ||
| * Refresh the model instance data retrieving | ||
| * model data using the main primary key. The | ||
| * existing model instance WILL BE affected. | ||
| */ | ||
| async refresh() { | ||
| const Model = this.constructor; | ||
| const schema = Model.schema(); | ||
| const relations = schema.getRelationProperties(); | ||
| const primaryKey = schema.getMainPrimaryKeyProperty(); | ||
| const query = Model.query() | ||
| .where(primaryKey, this[primaryKey]) | ||
| .withTrashed(); | ||
| Object.keys(this).forEach(key => { | ||
| if (!relations.includes(key)) { | ||
| return; | ||
| } | ||
| query.with(key); | ||
| }); | ||
| const data = await query.find(); | ||
| Object.keys(data).forEach(key => (this[key] = data[key])); | ||
| } | ||
| /** | ||
| * Verify if model is soft deleted. | ||
| */ | ||
| isTrashed() { | ||
| const Model = this.constructor; | ||
| const deletedAt = Model.schema().getDeletedAtColumn(); | ||
| return !!this[deletedAt.property]; | ||
| } | ||
| /** | ||
| * Delete or soft delete your model from database. | ||
| */ | ||
| async delete(force = false) { | ||
| const Model = this.constructor; | ||
| const primaryKey = Model.schema().getMainPrimaryKeyProperty(); | ||
| await Model.query().where(primaryKey, this[primaryKey]).delete(force); | ||
| } | ||
| /** | ||
| * Restore a soft deleted model from database. | ||
| */ | ||
| async restore() { | ||
| const Model = this.constructor; | ||
| const primaryKey = Model.schema().getMainPrimaryKeyProperty(); | ||
| const restored = await Model.query() | ||
| .where(primaryKey, this[primaryKey]) | ||
| .restore(); | ||
| Object.keys(restored).forEach(key => (this[key] = restored[key])); | ||
| return this; | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Collection, type PaginationOptions } from '@athenna/common'; | ||
| import type { Direction, Operations, ModelColumns, ModelRelations } from '#src/types'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { Driver } from '#src/database/drivers/Driver'; | ||
| import { QueryBuilder } from '#src/database/builders/QueryBuilder'; | ||
| import type { Transaction } from '#src/database/transactions/Transaction'; | ||
| export declare class ModelQueryBuilder<M extends BaseModel = any, D extends Driver = any> extends QueryBuilder<M, D> { | ||
| private Model; | ||
| private schema; | ||
| private generator; | ||
| private primaryKeyName; | ||
| private primaryKeyProperty; | ||
| private isToSetAttributes; | ||
| private isToValidateUnique; | ||
| private isToValidateNullable; | ||
| private selectColumns; | ||
| private DELETED_AT_PROP; | ||
| private DELETED_AT_NAME; | ||
| private isSoftDelete; | ||
| private hasCustomSelect; | ||
| constructor(model: any, driver: D); | ||
| /** | ||
| * Define a transaction to be used by the model query builder. | ||
| */ | ||
| setTransaction(trx: Transaction): this; | ||
| /** | ||
| * Set a different driver to the model query builder. | ||
| */ | ||
| setDriver(driver: Driver, tableName?: string): this; | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| avg(column: ModelColumns<M>): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| avgDistinct(column: ModelColumns<M>): Promise<string>; | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| max(column: ModelColumns<M>): Promise<string>; | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| min(column: ModelColumns<M>): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| sum(column: ModelColumns<M>): Promise<string>; | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| sumDistinct(column: ModelColumns<M>): Promise<string>; | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| increment(column: ModelColumns<M>): Promise<void>; | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| decrement(column: ModelColumns<M>): Promise<void>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| count(column?: ModelColumns<M>): Promise<string>; | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| countDistinct(column: ModelColumns<M>): Promise<string>; | ||
| /** | ||
| * Find value in database but returns only the value of | ||
| * selected column directly. | ||
| */ | ||
| pluck<K extends keyof M = ModelColumns<M>>(column: K): Promise<M[K]>; | ||
| /** | ||
| * Find many values in database but returns only the | ||
| * values of selected column directly. | ||
| */ | ||
| pluckMany<K extends keyof M = ModelColumns<M>>(column: K): Promise<M[K][]>; | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| find(): Promise<M>; | ||
| /** | ||
| * Find a value in database or throw exception if undefined. | ||
| */ | ||
| findOrFail(): Promise<M>; | ||
| /** | ||
| * Return a single data or, if no results are found, | ||
| * execute the given closure. | ||
| */ | ||
| findOr<T = M>(closure: () => T | Promise<T>): Promise<T>; | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| findMany(): Promise<M[]>; | ||
| /** | ||
| * Find many values in database and return paginated. | ||
| */ | ||
| paginate(page?: PaginationOptions | number, limit?: number, resourceUrl?: string): Promise<import("@athenna/common").PaginatedResponse<any>>; | ||
| /** | ||
| * Find many values in database and return | ||
| * as a collection instance. | ||
| */ | ||
| collection(): Promise<Collection<M>>; | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| create(data?: Partial<M>, cleanPersist?: boolean): Promise<M>; | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| createMany(data: Partial<M>[], cleanPersist?: boolean): Promise<M[]>; | ||
| /** | ||
| * Create or update a value in database. | ||
| */ | ||
| createOrUpdate(data: Partial<M>, cleanPersist?: boolean): Promise<M | M[]>; | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| update(data: Partial<M>, cleanPersist?: boolean): Promise<M | M[]>; | ||
| /** | ||
| * Delete or soft delete a value in database. | ||
| */ | ||
| delete(force?: boolean): Promise<void>; | ||
| /** | ||
| * Restore one or multiple soft deleted models. | ||
| */ | ||
| restore(): Promise<M | M[]>; | ||
| /** | ||
| * Retrieve only the values that are soft deleted in | ||
| * database. | ||
| */ | ||
| onlyTrashed(): this; | ||
| /** | ||
| * Retrieve values that are soft deleted in database. | ||
| */ | ||
| withTrashed(): this; | ||
| /** | ||
| * Enable/disable setting the default attributes properties | ||
| * when creating/updating models. | ||
| */ | ||
| setAttributes(value: boolean): this; | ||
| /** | ||
| * Enable/disable the `isUnique` property validation of | ||
| * models columns. | ||
| */ | ||
| uniqueValidation(value: boolean): this; | ||
| /** | ||
| * Enable/disable the `isNullable` property validation of | ||
| * models columns. | ||
| */ | ||
| nullableValidation(value: boolean): this; | ||
| with(relation: string): this; | ||
| with<K extends ModelRelations<M>>(relation: K, closure?: (query: ModelQueryBuilder<Extract<M[K] extends BaseModel[] ? M[K][0] : M[K], BaseModel>, Driver>) => any): this; | ||
| /** | ||
| * Only returns the data if the closure returns a result. | ||
| */ | ||
| whereHas<K extends ModelRelations<M>>(relation: K | string, closure?: (query: ModelQueryBuilder<Extract<M[K] extends BaseModel[] ? M[K][0] : M[K], BaseModel>, Driver>) => any): this; | ||
| /** | ||
| * Executes the given closure when the first argument is true. | ||
| */ | ||
| when(criteria: any, closure: (query: this, criteriaValue: any) => any | Promise<any>): this; | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| select(...columns: ModelColumns<M>[]): this; | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| groupBy(...columns: ModelColumns<M>[]): this; | ||
| having(column: ModelColumns<M>): this; | ||
| having(column: ModelColumns<M>, value: any): this; | ||
| having(column: ModelColumns<M>, operation: Operations, value: any): this; | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| havingIn(column: ModelColumns<M>, values: any[]): this; | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| havingNotIn(column: ModelColumns<M>, values: any[]): this; | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| havingBetween(column: ModelColumns<M>, values: [any, any]): this; | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| havingNotBetween(column: ModelColumns<M>, values: [any, any]): this; | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| havingNull(column: ModelColumns<M>): this; | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| havingNotNull(column: ModelColumns<M>): this; | ||
| orHaving(column: ModelColumns<M>): this; | ||
| orHaving(column: ModelColumns<M>, value: any): this; | ||
| orHaving(column: ModelColumns<M>, operation: Operations, value: any): this; | ||
| /** | ||
| * Set a orHaving in statement in your query. | ||
| */ | ||
| orHavingIn(column: ModelColumns<M>, values: any[]): this; | ||
| /** | ||
| * Set a orHaving not in statement in your query. | ||
| */ | ||
| orHavingNotIn(column: ModelColumns<M>, values: any[]): this; | ||
| /** | ||
| * Set a orHaving between statement in your query. | ||
| */ | ||
| orHavingBetween(column: ModelColumns<M>, values: [any, any]): this; | ||
| /** | ||
| * Set a orHaving not between statement in your query. | ||
| */ | ||
| orHavingNotBetween(column: ModelColumns<M>, values: [any, any]): this; | ||
| /** | ||
| * Set a orHaving null statement in your query. | ||
| */ | ||
| orHavingNull(column: ModelColumns<M>): this; | ||
| /** | ||
| * Set a orHaving not null statement in your query. | ||
| */ | ||
| orHavingNotNull(column: ModelColumns<M>): this; | ||
| where(statement: (query: this) => void): this; | ||
| where(statement: Partial<M>): this; | ||
| where(statement: Record<string, any>): this; | ||
| where(key: ModelColumns<M>, value: any): this; | ||
| where(key: ModelColumns<M>, operation: Operations, value: any): this; | ||
| whereNot(statement: (query: this) => void): this; | ||
| whereNot(statement: Partial<M>): this; | ||
| whereNot(statement: Record<string, any>): this; | ||
| whereNot(key: ModelColumns<M>, value: any): this; | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| whereLike(column: ModelColumns<M>, value: any): this; | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| whereILike(column: ModelColumns<M>, value: any): this; | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| whereIn(column: ModelColumns<M>, values: any[]): this; | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| whereNotIn(column: ModelColumns<M>, values: any[]): this; | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| whereBetween(column: ModelColumns<M>, values: [any, any]): this; | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| whereNotBetween(column: ModelColumns<M>, values: [any, any]): this; | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| whereNull(column: ModelColumns<M>): this; | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| whereNotNull(column: ModelColumns<M>): this; | ||
| orWhere(statement: (query: this) => void): this; | ||
| orWhere(statement: Partial<M>): this; | ||
| orWhere(statement: Record<string, any>): this; | ||
| orWhere(key: ModelColumns<M>, value: any): this; | ||
| orWhere(key: ModelColumns<M>, operation: Operations, value: any): this; | ||
| orWhereNot(statement: (query: this) => void): this; | ||
| orWhereNot(statement: Partial<M>): this; | ||
| orWhereNot(statement: Record<string, any>): this; | ||
| orWhereNot(key: ModelColumns<M>, value: any): this; | ||
| orWhereLike(statement: Partial<M>): this; | ||
| orWhereLike(statement: Record<string, any>): this; | ||
| orWhereLike(key: ModelColumns<M>, value: any): this; | ||
| orWhereILike(statement: Partial<M>): this; | ||
| orWhereILike(statement: Record<string, any>): this; | ||
| orWhereILike(key: ModelColumns<M>, value: any): this; | ||
| /** | ||
| * Set a orWhere in statement in your query. | ||
| */ | ||
| orWhereIn(column: ModelColumns<M>, values: any[]): this; | ||
| /** | ||
| * Set a orWhere not in statement in your query. | ||
| */ | ||
| orWhereNotIn(column: ModelColumns<M>, values: any[]): this; | ||
| /** | ||
| * Set a orWhere between statement in your query. | ||
| */ | ||
| orWhereBetween(column: ModelColumns<M>, values: [any, any]): this; | ||
| /** | ||
| * Set a orWhere not between statement in your query. | ||
| */ | ||
| orWhereNotBetween(column: ModelColumns<M>, values: [any, any]): this; | ||
| /** | ||
| * Set a orWhere null statement in your query. | ||
| */ | ||
| orWhereNull(column: ModelColumns<M>): this; | ||
| /** | ||
| * Set a orWhere not null statement in your query. | ||
| */ | ||
| orWhereNotNull(column: ModelColumns<M>): this; | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| orderBy(column: ModelColumns<M>, direction?: Direction): this; | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| latest(column?: ModelColumns<M>): this; | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| oldest(column?: ModelColumns<M>): this; | ||
| /** | ||
| * Set the internal selected properties and soft delete | ||
| * queries. | ||
| */ | ||
| private setInternalQueries; | ||
| /** | ||
| * Verify that columns with `isNullable` property | ||
| * can be created in database. | ||
| */ | ||
| private validateNullable; | ||
| /** | ||
| * Verify that columns with isUnique property | ||
| * can be created in database. | ||
| */ | ||
| private validateUnique; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Collection, Is, Options } from '@athenna/common'; | ||
| import { QueryBuilder } from '#src/database/builders/QueryBuilder'; | ||
| import { ModelGenerator } from '#src/models/factories/ModelGenerator'; | ||
| import { UniqueValueException } from '#src/exceptions/UniqueValueException'; | ||
| import { HasOneRelation } from '#src/models/relations/HasOne/HasOneRelation'; | ||
| import { NotFoundDataException } from '#src/exceptions/NotFoundDataException'; | ||
| import { HasManyRelation } from '#src/models/relations/HasMany/HasManyRelation'; | ||
| import { NullableValueException } from '#src/exceptions/NullableValueException'; | ||
| import { BelongsToRelation } from '#src/models/relations/BelongsTo/BelongsToRelation'; | ||
| import { BelongsToManyRelation } from '#src/models/relations/BelongsToMany/BelongsToManyRelation'; | ||
| export class ModelQueryBuilder extends QueryBuilder { | ||
| constructor(model, driver) { | ||
| super(driver, model.table()); | ||
| this.isToSetAttributes = true; | ||
| this.isToValidateUnique = true; | ||
| this.isToValidateNullable = true; | ||
| this.selectColumns = []; | ||
| this.DELETED_AT_PROP = null; | ||
| this.DELETED_AT_NAME = null; | ||
| this.isSoftDelete = false; | ||
| this.hasCustomSelect = false; | ||
| this.Model = model; | ||
| this.schema = model.schema(); | ||
| this.generator = new ModelGenerator(this.Model, this.schema); | ||
| this.primaryKeyName = this.schema.getMainPrimaryKeyName(); | ||
| this.primaryKeyProperty = this.schema.getMainPrimaryKeyProperty(); | ||
| const deletedAtColumn = this.schema.getDeletedAtColumn(); | ||
| if (deletedAtColumn) { | ||
| this.isSoftDelete = true; | ||
| this.DELETED_AT_NAME = deletedAtColumn.name; | ||
| this.DELETED_AT_PROP = deletedAtColumn.property; | ||
| } | ||
| this.selectColumns = this.schema.getAllColumnNames(); | ||
| this.setPrimaryKey(this.primaryKeyName); | ||
| } | ||
| /** | ||
| * Define a transaction to be used by the model query builder. | ||
| */ | ||
| setTransaction(trx) { | ||
| return this.setDriver(trx.driver, this.Model.table()); | ||
| } | ||
| /** | ||
| * Set a different driver to the model query builder. | ||
| */ | ||
| setDriver(driver, tableName) { | ||
| super.setDriver(driver, tableName); | ||
| return this; | ||
| } | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| async avg(column) { | ||
| this.setInternalQueries(); | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| return super.avg(name); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column. | ||
| */ | ||
| async avgDistinct(column) { | ||
| this.setInternalQueries(); | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| return super.avgDistinct(name); | ||
| } | ||
| /** | ||
| * Get the max number of a given column. | ||
| */ | ||
| async max(column) { | ||
| this.setInternalQueries(); | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| return super.max(name); | ||
| } | ||
| /** | ||
| * Get the min number of a given column. | ||
| */ | ||
| async min(column) { | ||
| this.setInternalQueries(); | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| return super.min(name); | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| async sum(column) { | ||
| this.setInternalQueries(); | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| return super.sum(name); | ||
| } | ||
| /** | ||
| * Sum all numbers of a given column. | ||
| */ | ||
| async sumDistinct(column) { | ||
| this.setInternalQueries(); | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| return super.sumDistinct(name); | ||
| } | ||
| /** | ||
| * Increment a value of a given column. | ||
| */ | ||
| async increment(column) { | ||
| this.setInternalQueries(); | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| return super.increment(name); | ||
| } | ||
| /** | ||
| * Decrement a value of a given column. | ||
| */ | ||
| async decrement(column) { | ||
| this.setInternalQueries(); | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| await super.decrement(name); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async count(column) { | ||
| this.setInternalQueries(); | ||
| if (!column) { | ||
| return super.count(); | ||
| } | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| return super.count(name); | ||
| } | ||
| /** | ||
| * Calculate the average of a given column using distinct. | ||
| */ | ||
| async countDistinct(column) { | ||
| this.setInternalQueries(); | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| return super.countDistinct(name); | ||
| } | ||
| /** | ||
| * Find value in database but returns only the value of | ||
| * selected column directly. | ||
| */ | ||
| async pluck(column) { | ||
| this.setInternalQueries(); | ||
| const columnName = this.schema.getColumnNameByProperty(column); | ||
| return super.pluck(columnName); | ||
| } | ||
| /** | ||
| * Find many values in database but returns only the | ||
| * values of selected column directly. | ||
| */ | ||
| async pluckMany(column) { | ||
| this.setInternalQueries(); | ||
| const columnName = this.schema.getColumnNameByProperty(column); | ||
| return super.pluckMany(columnName); | ||
| } | ||
| /** | ||
| * Find a value in database. | ||
| */ | ||
| async find() { | ||
| this.setInternalQueries(); | ||
| const data = await super.find(); | ||
| return this.generator.generateOne(data); | ||
| } | ||
| /** | ||
| * Find a value in database or throw exception if undefined. | ||
| */ | ||
| async findOrFail() { | ||
| const data = await this.find(); | ||
| if (!data) { | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| throw new NotFoundDataException(this.Model.connection()); | ||
| } | ||
| return data; | ||
| } | ||
| /** | ||
| * Return a single data or, if no results are found, | ||
| * execute the given closure. | ||
| */ | ||
| async findOr(closure) { | ||
| const data = (await this.find()); | ||
| if (!data) { | ||
| return closure(); | ||
| } | ||
| return data; | ||
| } | ||
| /** | ||
| * Find many values in database. | ||
| */ | ||
| async findMany() { | ||
| this.setInternalQueries(); | ||
| const data = await super.findMany(); | ||
| return this.generator.generateMany(data); | ||
| } | ||
| /** | ||
| * Find many values in database and return paginated. | ||
| */ | ||
| async paginate(page = { page: 0, limit: 10, resourceUrl: '/' }, limit = 10, resourceUrl = '/') { | ||
| this.setInternalQueries(); | ||
| const data = await super.paginate(page, limit, resourceUrl); | ||
| data.data = await this.generator.generateMany(data.data); | ||
| return data; | ||
| } | ||
| /** | ||
| * Find many values in database and return | ||
| * as a collection instance. | ||
| */ | ||
| async collection() { | ||
| const models = await this.findMany(); | ||
| return new Collection(models); | ||
| } | ||
| /** | ||
| * Create a value in database. | ||
| */ | ||
| async create(data = {}, cleanPersist = true) { | ||
| const created = await this.createMany([data], cleanPersist); | ||
| return created[0]; | ||
| } | ||
| /** | ||
| * Create many values in database. | ||
| */ | ||
| async createMany(data, cleanPersist = true) { | ||
| data = await Promise.all(data.map(async (d) => { | ||
| const date = new Date(); | ||
| const createdAt = this.schema.getCreatedAtColumn(); | ||
| const updatedAt = this.schema.getUpdatedAtColumn(); | ||
| const deletedAt = this.schema.getDeletedAtColumn(); | ||
| const attributes = this.isToSetAttributes ? this.Model.attributes() : {}; | ||
| const parsed = this.schema.propertiesToColumnNames(d, { | ||
| attributes, | ||
| cleanPersist | ||
| }); | ||
| if (createdAt && parsed[createdAt.name] === undefined) { | ||
| parsed[createdAt.name] = date; | ||
| } | ||
| if (updatedAt && parsed[updatedAt.name] === undefined) { | ||
| parsed[updatedAt.name] = date; | ||
| } | ||
| if (deletedAt && parsed[deletedAt.name] === undefined) { | ||
| parsed[deletedAt.name] = null; | ||
| } | ||
| this.validateNullable(parsed); | ||
| await this.validateUnique(parsed); | ||
| return parsed; | ||
| })); | ||
| const created = await super.createMany(data); | ||
| return this.generator.generateMany(created); | ||
| } | ||
| /** | ||
| * Create or update a value in database. | ||
| */ | ||
| async createOrUpdate(data, cleanPersist = true) { | ||
| const hasValue = await this.find(); | ||
| if (hasValue) { | ||
| const pk = this.primaryKeyProperty; | ||
| return this.where(pk, hasValue[pk]).update(data, cleanPersist); | ||
| } | ||
| return this.create(data, cleanPersist); | ||
| } | ||
| /** | ||
| * Update a value in database. | ||
| */ | ||
| async update(data, cleanPersist = true) { | ||
| this.setInternalQueries(); | ||
| const date = new Date(); | ||
| const updatedAt = this.schema.getUpdatedAtColumn(); | ||
| const attributes = this.isToSetAttributes ? this.Model.attributes() : {}; | ||
| const parsed = this.schema.propertiesToColumnNames(data, { | ||
| attributes, | ||
| cleanPersist | ||
| }); | ||
| if (updatedAt && parsed[updatedAt.name] === undefined) { | ||
| parsed[updatedAt.name] = date; | ||
| } | ||
| await this.validateUnique(parsed, true); | ||
| const updated = await super.update(parsed); | ||
| if (Is.Array(updated)) { | ||
| return this.generator.generateMany(updated); | ||
| } | ||
| return this.generator.generateOne(updated); | ||
| } | ||
| /** | ||
| * Delete or soft delete a value in database. | ||
| */ | ||
| async delete(force = false) { | ||
| this.setInternalQueries({ addSelect: false }); | ||
| if (!this.DELETED_AT_NAME || force) { | ||
| await super.delete(); | ||
| return; | ||
| } | ||
| await this.update({ [this.DELETED_AT_PROP]: new Date() }); | ||
| } | ||
| /** | ||
| * Restore one or multiple soft deleted models. | ||
| */ | ||
| async restore() { | ||
| this.setInternalQueries({ addSoftDelete: false }); | ||
| if (!this.DELETED_AT_PROP) { | ||
| return; | ||
| } | ||
| const updatedAt = this.schema.getUpdatedAtColumn(); | ||
| const data = { [this.DELETED_AT_PROP]: null }; | ||
| if (updatedAt) { | ||
| data[updatedAt.name] = new Date(); | ||
| } | ||
| const updated = await super.update(data); | ||
| if (Is.Array(updated)) { | ||
| return this.generator.generateMany(updated); | ||
| } | ||
| return this.generator.generateOne(updated); | ||
| } | ||
| /** | ||
| * Retrieve only the values that are soft deleted in | ||
| * database. | ||
| */ | ||
| onlyTrashed() { | ||
| this.isSoftDelete = false; | ||
| if (!this.DELETED_AT_PROP) { | ||
| return this; | ||
| } | ||
| return this.whereNotNull(this.DELETED_AT_PROP); | ||
| } | ||
| /** | ||
| * Retrieve values that are soft deleted in database. | ||
| */ | ||
| withTrashed() { | ||
| this.isSoftDelete = false; | ||
| if (!this.DELETED_AT_PROP) { | ||
| return this; | ||
| } | ||
| if (this.schema.getModelDriverName() === 'mongo') { | ||
| this.orWhereNull(this.DELETED_AT_PROP); | ||
| } | ||
| return this.orWhereNotNull(this.DELETED_AT_PROP); | ||
| } | ||
| /** | ||
| * Enable/disable setting the default attributes properties | ||
| * when creating/updating models. | ||
| */ | ||
| setAttributes(value) { | ||
| this.isToSetAttributes = value; | ||
| return this; | ||
| } | ||
| /** | ||
| * Enable/disable the `isUnique` property validation of | ||
| * models columns. | ||
| */ | ||
| uniqueValidation(value) { | ||
| this.isToValidateUnique = value; | ||
| return this; | ||
| } | ||
| /** | ||
| * Enable/disable the `isNullable` property validation of | ||
| * models columns. | ||
| */ | ||
| nullableValidation(value) { | ||
| this.isToValidateNullable = value; | ||
| return this; | ||
| } | ||
| /** | ||
| * Eager load a relation in your query. | ||
| */ | ||
| with(relation, closure) { | ||
| this.schema.includeRelation(relation, closure); | ||
| return this; | ||
| } | ||
| /** | ||
| * Only returns the data if the closure returns a result. | ||
| */ | ||
| whereHas(relation, closure) { | ||
| const options = this.schema.includeRelation(relation, closure); | ||
| super.whereExists(query => { | ||
| switch (options.type) { | ||
| case 'hasOne': | ||
| return HasOneRelation.whereHas(this.Model, query, options); | ||
| case 'hasMany': | ||
| return HasManyRelation.whereHas(this.Model, query, options); | ||
| case 'belongsTo': | ||
| return BelongsToRelation.whereHas(this.Model, query, options); | ||
| case 'belongsToMany': | ||
| return BelongsToManyRelation.whereHas(this.Model, query, options); | ||
| } | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Executes the given closure when the first argument is true. | ||
| */ | ||
| when(criteria, closure) { | ||
| if (criteria) { | ||
| closure(this, criteria); | ||
| return this; | ||
| } | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the columns that should be selected on query. | ||
| */ | ||
| select(...columns) { | ||
| if (!this.hasCustomSelect) { | ||
| this.hasCustomSelect = true; | ||
| this.selectColumns = columns.map(c => this.schema.getColumnNameByProperty(c)); | ||
| return this; | ||
| } | ||
| columns.forEach(column => { | ||
| const index = this.selectColumns.indexOf(column); | ||
| if (index) { | ||
| return; | ||
| } | ||
| this.selectColumns.push(this.schema.getColumnNameByProperty(column)); | ||
| }); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a group by statement in your query. | ||
| */ | ||
| groupBy(...columns) { | ||
| super.groupBy(...this.schema.getColumnNamesByProperties(columns)); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having statement in your query. | ||
| */ | ||
| having(column, operation, value) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.having(name, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having in statement in your query. | ||
| */ | ||
| havingIn(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.havingIn(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not in statement in your query. | ||
| */ | ||
| havingNotIn(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.havingNotIn(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having between statement in your query. | ||
| */ | ||
| havingBetween(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.havingBetween(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not between statement in your query. | ||
| */ | ||
| havingNotBetween(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.havingNotBetween(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having null statement in your query. | ||
| */ | ||
| havingNull(column) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.havingNull(name); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a having not null statement in your query. | ||
| */ | ||
| havingNotNull(column) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.havingNotNull(name); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orHaving statement in your query. | ||
| */ | ||
| orHaving(column, operation, value) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orHaving(name, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orHaving in statement in your query. | ||
| */ | ||
| orHavingIn(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orHavingIn(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orHaving not in statement in your query. | ||
| */ | ||
| orHavingNotIn(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orHavingNotIn(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orHaving between statement in your query. | ||
| */ | ||
| orHavingBetween(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orHavingBetween(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orHaving not between statement in your query. | ||
| */ | ||
| orHavingNotBetween(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orHavingNotBetween(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orHaving null statement in your query. | ||
| */ | ||
| orHavingNull(column) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orHavingNull(name); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orHaving not null statement in your query. | ||
| */ | ||
| orHavingNotNull(column) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orHavingNotNull(name); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where statement in your query. | ||
| */ | ||
| where(statement, operation, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.driver.clone(); | ||
| super.where(query => { | ||
| const modelQb = new ModelQueryBuilder(this.Model, driver.setQueryBuilder(query, { useSetQB: true })); | ||
| statement(modelQb); | ||
| }); | ||
| return this; | ||
| } | ||
| if (!operation) { | ||
| const parsed = this.schema.propertiesToColumnNames(statement); | ||
| super.where(parsed); | ||
| return this; | ||
| } | ||
| const name = this.schema.getColumnNameByProperty(statement); | ||
| super.where(name, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not statement in your query. | ||
| */ | ||
| whereNot(statement, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.driver.clone(); | ||
| super.whereNot(query => { | ||
| const modelQb = new ModelQueryBuilder(this.Model, driver.setQueryBuilder(query, { useSetQB: true })); | ||
| statement(modelQb); | ||
| }); | ||
| return this; | ||
| } | ||
| if (!value) { | ||
| const parsed = this.schema.propertiesToColumnNames(statement); | ||
| super.whereNot(parsed); | ||
| return this; | ||
| } | ||
| const name = this.schema.getColumnNameByProperty(statement); | ||
| super.whereNot(name, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where like statement in your query. | ||
| */ | ||
| whereLike(column, value) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.whereLike(name, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where ILike statement in your query. | ||
| */ | ||
| whereILike(column, value) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.whereILike(name, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where in statement in your query. | ||
| */ | ||
| whereIn(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.whereIn(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not in statement in your query. | ||
| */ | ||
| whereNotIn(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.whereNotIn(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where between statement in your query. | ||
| */ | ||
| whereBetween(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.whereBetween(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not between statement in your query. | ||
| */ | ||
| whereNotBetween(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.whereNotBetween(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where null statement in your query. | ||
| */ | ||
| whereNull(column) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.whereNull(name); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a where not null statement in your query. | ||
| */ | ||
| whereNotNull(column) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.whereNotNull(name); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orWhere statement in your query. | ||
| */ | ||
| orWhere(statement, operation, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.driver.clone(); | ||
| super.orWhere(query => { | ||
| const modelQb = new ModelQueryBuilder(this.Model, driver.setQueryBuilder(query, { useSetQB: true })); | ||
| statement(modelQb); | ||
| }); | ||
| return this; | ||
| } | ||
| if (!operation) { | ||
| const parsed = this.schema.propertiesToColumnNames(statement); | ||
| super.orWhere(parsed); | ||
| return this; | ||
| } | ||
| const name = this.schema.getColumnNameByProperty(statement); | ||
| super.orWhere(name, operation, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orWhere not statement in your query. | ||
| */ | ||
| orWhereNot(statement, value) { | ||
| if (Is.Function(statement)) { | ||
| const driver = this.driver.clone(); | ||
| super.orWhereNot(query => { | ||
| const modelQb = new ModelQueryBuilder(this.Model, driver.setQueryBuilder(query, { useSetQB: true })); | ||
| statement(modelQb); | ||
| }); | ||
| return this; | ||
| } | ||
| if (!value) { | ||
| const parsed = this.schema.propertiesToColumnNames(statement); | ||
| super.orWhereNot(parsed); | ||
| return this; | ||
| } | ||
| const name = this.schema.getColumnNameByProperty(statement); | ||
| super.orWhereNot(name, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orWhere like statement in your query. | ||
| */ | ||
| orWhereLike(statement, value) { | ||
| if (!value) { | ||
| const parsed = this.schema.propertiesToColumnNames(statement); | ||
| super.orWhereLike(parsed); | ||
| return this; | ||
| } | ||
| const name = this.schema.getColumnNameByProperty(statement); | ||
| super.orWhereLike(name, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orWhere ILike statement in your query. | ||
| */ | ||
| orWhereILike(statement, value) { | ||
| if (!value) { | ||
| const parsed = this.schema.propertiesToColumnNames(statement); | ||
| super.orWhereILike(parsed); | ||
| return this; | ||
| } | ||
| const name = this.schema.getColumnNameByProperty(statement); | ||
| super.orWhereILike(name, value); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orWhere in statement in your query. | ||
| */ | ||
| orWhereIn(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orWhereIn(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orWhere not in statement in your query. | ||
| */ | ||
| orWhereNotIn(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orWhereNotIn(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orWhere between statement in your query. | ||
| */ | ||
| orWhereBetween(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orWhereBetween(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orWhere not between statement in your query. | ||
| */ | ||
| orWhereNotBetween(column, values) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orWhereNotBetween(name, values); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orWhere null statement in your query. | ||
| */ | ||
| orWhereNull(column) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orWhereNull(name); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set a orWhere not null statement in your query. | ||
| */ | ||
| orWhereNotNull(column) { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orWhereNotNull(name); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set an order by statement in your query. | ||
| */ | ||
| orderBy(column, direction = 'ASC') { | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.orderBy(name, direction); | ||
| return this; | ||
| } | ||
| /** | ||
| * Order the results easily by the latest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| latest(column) { | ||
| if (!column) { | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| column = 'createdAt'; | ||
| } | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.latest(name); | ||
| return this; | ||
| } | ||
| /** | ||
| * Order the results easily by the oldest date. By default, the result will | ||
| * be ordered by the table's "createdAt" column. | ||
| */ | ||
| oldest(column) { | ||
| if (!column) { | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| column = 'createdAt'; | ||
| } | ||
| const name = this.schema.getColumnNameByProperty(column); | ||
| super.oldest(name); | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the internal selected properties and soft delete | ||
| * queries. | ||
| */ | ||
| setInternalQueries(options) { | ||
| options = Options.create(options, { | ||
| addSelect: true, | ||
| addSoftDelete: true | ||
| }); | ||
| if (options.addSelect) { | ||
| super.select(...this.selectColumns); | ||
| } | ||
| if (options.addSoftDelete) { | ||
| super.when(this.isSoftDelete, query => query.whereNull(this.DELETED_AT_NAME)); | ||
| } | ||
| } | ||
| /** | ||
| * Verify that columns with `isNullable` property | ||
| * can be created in database. | ||
| */ | ||
| validateNullable(data) { | ||
| if (!this.isToValidateNullable) { | ||
| return; | ||
| } | ||
| const records = []; | ||
| for (const column of this.schema.getAllNotNullableColumns()) { | ||
| const value = data[column.name]; | ||
| if (value === undefined || value === null) { | ||
| records.push(column.property); | ||
| } | ||
| } | ||
| if (!Is.Empty(records)) { | ||
| throw new NullableValueException(records); | ||
| } | ||
| } | ||
| /** | ||
| * Verify that columns with isUnique property | ||
| * can be created in database. | ||
| */ | ||
| async validateUnique(data, isUpdate = false) { | ||
| if (!this.isToValidateUnique) { | ||
| return; | ||
| } | ||
| const records = {}; | ||
| for (const column of this.schema.getAllUniqueColumns()) { | ||
| const value = data[column.name]; | ||
| if (value === undefined) { | ||
| continue; | ||
| } | ||
| if (isUpdate) { | ||
| const data = await this.Model.query() | ||
| .where(column.name, value) | ||
| .findMany(); | ||
| if (data.length > 1) { | ||
| records[column.property] = value; | ||
| continue; | ||
| } | ||
| } | ||
| const isDuplicated = await this.Model.query() | ||
| .where(column.name, value) | ||
| .exists(); | ||
| if (isDuplicated) { | ||
| records[column.property] = value; | ||
| } | ||
| } | ||
| if (!Is.Empty(records)) { | ||
| throw new UniqueValueException(records); | ||
| } | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Macroable } from '@athenna/common'; | ||
| import { BaseModel } from '#src/models/BaseModel'; | ||
| export declare class ModelFactory<M extends BaseModel = any, R = M> extends Macroable { | ||
| /** | ||
| * The model that will be used to fabricate | ||
| * instances from. | ||
| */ | ||
| private Model; | ||
| /** | ||
| * The number of models to be created. | ||
| */ | ||
| private _count; | ||
| /** | ||
| * Set if the soft delete state is active or not. | ||
| */ | ||
| private _trashed; | ||
| /** | ||
| * Set the returning key that this factory will return. | ||
| */ | ||
| private _returning; | ||
| constructor(model: typeof BaseModel); | ||
| returning(key: '*'): ModelFactory<M>; | ||
| returning<T extends keyof M>(key: T): ModelFactory<M, M[T]>; | ||
| /** | ||
| * Same as returning method, but return the type of | ||
| * the key of the model to avoid using "as any" or | ||
| * other kind of stuffs to fix the type in definition | ||
| * method. | ||
| * | ||
| * Only the type is modified for convenience, the real | ||
| * return type of this method is still the ModelFactory | ||
| * instance. | ||
| */ | ||
| returningAs<T extends keyof M>(key: T): M[T]; | ||
| /** | ||
| * Set the soft delete state in your model to | ||
| * fabricate deleted data. | ||
| */ | ||
| trashed(): this; | ||
| /** | ||
| * Remove the soft delete state in your model to | ||
| * not fabricate deleted data. | ||
| */ | ||
| untrashed(): this; | ||
| count(number: 1): ModelFactory<M, R>; | ||
| count(number: number): ModelFactory<M, R[]>; | ||
| /** | ||
| * Make models without creating it on database. | ||
| */ | ||
| make(override?: Partial<M>): Promise<R>; | ||
| /** | ||
| * Create models creating it on database. | ||
| */ | ||
| create(override?: Partial<M>): Promise<R>; | ||
| /** | ||
| * Execute the definition method and return data. | ||
| */ | ||
| private getDefinition; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { debug } from '#src/debug'; | ||
| import { Macroable } from '@athenna/common'; | ||
| import { BaseModel } from '#src/models/BaseModel'; | ||
| export class ModelFactory extends Macroable { | ||
| constructor(model) { | ||
| super(); | ||
| /** | ||
| * The number of models to be created. | ||
| */ | ||
| this._count = 1; | ||
| /** | ||
| * Set if the soft delete state is active or not. | ||
| */ | ||
| this._trashed = false; | ||
| /** | ||
| * Set the returning key that this factory will return. | ||
| */ | ||
| this._returning = '*'; | ||
| this.Model = model; | ||
| } | ||
| /** | ||
| * Set the returning key that this factory will | ||
| * return after making or creating an instance. | ||
| */ | ||
| returning(key) { | ||
| this._returning = key; | ||
| return this; | ||
| } | ||
| /** | ||
| * Same as returning method, but return the type of | ||
| * the key of the model to avoid using "as any" or | ||
| * other kind of stuffs to fix the type in definition | ||
| * method. | ||
| * | ||
| * Only the type is modified for convenience, the real | ||
| * return type of this method is still the ModelFactory | ||
| * instance. | ||
| */ | ||
| returningAs(key) { | ||
| this._returning = key; | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the soft delete state in your model to | ||
| * fabricate deleted data. | ||
| */ | ||
| trashed() { | ||
| this._trashed = true; | ||
| return this; | ||
| } | ||
| /** | ||
| * Remove the soft delete state in your model to | ||
| * not fabricate deleted data. | ||
| */ | ||
| untrashed() { | ||
| this._trashed = false; | ||
| return this; | ||
| } | ||
| /** | ||
| * Set the number of models to be created. | ||
| */ | ||
| count(number) { | ||
| this._count = number; | ||
| return this; | ||
| } | ||
| /** | ||
| * Make models without creating it on database. | ||
| */ | ||
| async make(override = {}) { | ||
| const promises = []; | ||
| for (let i = 1; i <= this._count; i++) { | ||
| promises.push(this.getDefinition(override, 'make')); | ||
| } | ||
| let data = await Promise.all(promises); | ||
| data = data.map(d => { | ||
| if (this._returning !== '*') { | ||
| return d[this._returning]; | ||
| } | ||
| const model = new this.Model(); | ||
| Object.keys(d).forEach(key => (model[key] = d[key])); | ||
| return model; | ||
| }); | ||
| if (this._count === 1) { | ||
| return data[0]; | ||
| } | ||
| return data; | ||
| } | ||
| /** | ||
| * Create models creating it on database. | ||
| */ | ||
| async create(override = {}) { | ||
| const promises = []; | ||
| for (let i = 1; i <= this._count; i++) { | ||
| promises.push(this.getDefinition(override, 'create')); | ||
| } | ||
| let data = await this.Model.createMany(await Promise.all(promises), false); | ||
| if (this._returning !== '*') { | ||
| data = data.map(d => d[this._returning]); | ||
| } | ||
| if (this._count === 1) { | ||
| return data[0]; | ||
| } | ||
| return data; | ||
| } | ||
| /** | ||
| * Execute the definition method and return data. | ||
| */ | ||
| async getDefinition(override, method) { | ||
| const data = await this.Model.definition(); | ||
| const promises = Object.keys(data).reduce((promises, key) => { | ||
| if ((override && override[key]) || !(data[key] instanceof ModelFactory)) { | ||
| return promises; | ||
| } | ||
| const SubFactory = data[key]; | ||
| const result = SubFactory[method]().then(r => (data[key] = r)); | ||
| promises.push(result); | ||
| return promises; | ||
| }, []); | ||
| await Promise.all(promises); | ||
| if (this._trashed) { | ||
| const column = this.Model.schema().getDeletedAtColumn(); | ||
| if (!column) { | ||
| debug('there is any column with isDeleteDate option as true in model %s. trashed option will be ignored.', this.Model.name); | ||
| } | ||
| else { | ||
| data[column.property] = new Date(); | ||
| } | ||
| } | ||
| return { | ||
| ...data, | ||
| ...override | ||
| }; | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Macroable } from '@athenna/common'; | ||
| import type { RelationOptions } from '#src/types'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import { ModelSchema } from '#src/models/schemas/ModelSchema'; | ||
| export declare class ModelGenerator<M extends BaseModel = any> extends Macroable { | ||
| /** | ||
| * The model that will be generated instances | ||
| * from. | ||
| */ | ||
| private Model; | ||
| /** | ||
| * The model schema that will be used to search | ||
| * for columns and relations. | ||
| */ | ||
| private schema; | ||
| constructor(model: new () => M, schema: ModelSchema<M>); | ||
| /** | ||
| * Generate one model instance with relations loaded. | ||
| */ | ||
| generateOne(data: any): Promise<M>; | ||
| /** | ||
| * Generate models instances with relations loaded. | ||
| */ | ||
| generateMany(data: any[]): Promise<M[]>; | ||
| /** | ||
| * Instantiate one model using vanilla database data. | ||
| */ | ||
| private instantiateOne; | ||
| /** | ||
| * Populate one object data in the model instance | ||
| * using the column dictionary to map keys. | ||
| */ | ||
| private populate; | ||
| /** | ||
| * Include one relation to one model. | ||
| */ | ||
| includeRelation(model: M, relation: RelationOptions): Promise<M>; | ||
| /** | ||
| * Include all relations to one model. | ||
| */ | ||
| private includeRelations; | ||
| /** | ||
| * Include one relation for all models. | ||
| */ | ||
| private includeRelationOfAll; | ||
| /** | ||
| * Include all relations for all models. | ||
| */ | ||
| private includeRelationsOfAll; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Macroable } from '@athenna/common'; | ||
| import { ObjectId } from '#src/helpers/ObjectId'; | ||
| import { ModelSchema } from '#src/models/schemas/ModelSchema'; | ||
| import { HasOneRelation } from '#src/models/relations/HasOne/HasOneRelation'; | ||
| import { HasManyRelation } from '#src/models/relations/HasMany/HasManyRelation'; | ||
| import { BelongsToRelation } from '#src/models/relations/BelongsTo/BelongsToRelation'; | ||
| import { BelongsToManyRelation } from '#src/models/relations/BelongsToMany/BelongsToManyRelation'; | ||
| export class ModelGenerator extends Macroable { | ||
| constructor(model, schema) { | ||
| super(); | ||
| this.Model = model; | ||
| // eslint-disable-next-line @typescript-eslint/ban-ts-comment | ||
| // @ts-ignore | ||
| this.schema = schema; | ||
| } | ||
| /** | ||
| * Generate one model instance with relations loaded. | ||
| */ | ||
| async generateOne(data) { | ||
| if (!data) { | ||
| return undefined; | ||
| } | ||
| const model = this.instantiateOne(data); | ||
| return this.includeRelations(model); | ||
| } | ||
| /** | ||
| * Generate models instances with relations loaded. | ||
| */ | ||
| async generateMany(data) { | ||
| if (!data || !data.length) { | ||
| return []; | ||
| } | ||
| const models = await Promise.all(data.map(d => this.instantiateOne(d))); | ||
| return this.includeRelationsOfAll(models); | ||
| } | ||
| /** | ||
| * Instantiate one model using vanilla database data. | ||
| */ | ||
| instantiateOne(data) { | ||
| return this.populate(data, new this.Model()); | ||
| } | ||
| /** | ||
| * Populate one object data in the model instance | ||
| * using the column dictionary to map keys. | ||
| */ | ||
| populate(object, model) { | ||
| Object.keys(object).forEach(key => { | ||
| const column = this.schema.getColumnByName(key); | ||
| if (!column) { | ||
| return; | ||
| } | ||
| if (ObjectId.isValidObject(object[key])) { | ||
| object[key] = object[key].toString(); | ||
| } | ||
| model[column.property] = object[key]; | ||
| }); | ||
| return model; | ||
| } | ||
| /** | ||
| * Include one relation to one model. | ||
| */ | ||
| async includeRelation(model, relation) { | ||
| switch (relation.type) { | ||
| case 'hasOne': | ||
| return HasOneRelation.load(model, relation); | ||
| case 'hasMany': | ||
| return HasManyRelation.load(model, relation); | ||
| case 'belongsTo': | ||
| return BelongsToRelation.load(model, relation); | ||
| case 'belongsToMany': | ||
| return BelongsToManyRelation.load(model, relation); | ||
| default: | ||
| return model; | ||
| } | ||
| } | ||
| /** | ||
| * Include all relations to one model. | ||
| */ | ||
| async includeRelations(model) { | ||
| const relations = this.schema.getIncludedRelations(); | ||
| if (!relations || !relations.length) { | ||
| return model.setOriginal(); | ||
| } | ||
| for (const relation of relations) { | ||
| model = await this.includeRelation(model, relation); | ||
| } | ||
| if (!model) { | ||
| return undefined; | ||
| } | ||
| return model.setOriginal(); | ||
| } | ||
| /** | ||
| * Include one relation for all models. | ||
| */ | ||
| async includeRelationOfAll(models, relation) { | ||
| switch (relation.type) { | ||
| case 'hasOne': | ||
| return HasOneRelation.loadAll(models, relation); | ||
| case 'hasMany': | ||
| return HasManyRelation.loadAll(models, relation); | ||
| case 'belongsTo': | ||
| return BelongsToRelation.loadAll(models, relation); | ||
| case 'belongsToMany': | ||
| return BelongsToManyRelation.loadAll(models, relation); | ||
| default: | ||
| return models; | ||
| } | ||
| } | ||
| /** | ||
| * Include all relations for all models. | ||
| */ | ||
| async includeRelationsOfAll(models) { | ||
| const relations = this.schema.getIncludedRelations(); | ||
| if (!relations || !relations.length) { | ||
| return models.map(model => model.setOriginal()); | ||
| } | ||
| for (const relation of relations) { | ||
| models = await this.includeRelationOfAll(models, relation); | ||
| } | ||
| return models.map(model => model.setOriginal()); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { BelongsToOptions } from '#src/types'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { Driver } from '#src/database/drivers/Driver'; | ||
| export declare class BelongsToRelation { | ||
| /** | ||
| * Get the options with defined default values. | ||
| */ | ||
| private static options; | ||
| /** | ||
| * Load a belongs to relation. | ||
| */ | ||
| static load(model: BaseModel, relation: BelongsToOptions): Promise<any>; | ||
| /** | ||
| * Load all models that belongs to relation. | ||
| */ | ||
| static loadAll(models: BaseModel[], relation: BelongsToOptions): Promise<any[]>; | ||
| /** | ||
| * Apply a where has relation to the query when the relation | ||
| * is a belongs to the given model. | ||
| */ | ||
| static whereHas(Model: typeof BaseModel, query: Driver, relation: BelongsToOptions): void; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { String } from '@athenna/common'; | ||
| export class BelongsToRelation { | ||
| /** | ||
| * Get the options with defined default values. | ||
| */ | ||
| static options(relation) { | ||
| const RelationModel = relation.model(); | ||
| relation.primaryKey = | ||
| relation.primaryKey || RelationModel.schema().getMainPrimaryKeyProperty(); | ||
| relation.foreignKey = | ||
| relation.foreignKey || `${String.toCamelCase(RelationModel.name)}Id`; | ||
| return relation; | ||
| } | ||
| /** | ||
| * Load a belongs to relation. | ||
| */ | ||
| static async load(model, relation) { | ||
| this.options(relation); | ||
| model[relation.property] = await relation | ||
| .model() | ||
| .query() | ||
| .where(relation.primaryKey, model[relation.foreignKey]) | ||
| .when(relation.closure, relation.closure) | ||
| .find(); | ||
| return model; | ||
| } | ||
| /** | ||
| * Load all models that belongs to relation. | ||
| */ | ||
| static async loadAll(models, relation) { | ||
| this.options(relation); | ||
| const foreignValues = models.map(model => model[relation.foreignKey]); | ||
| const results = await relation | ||
| .model() | ||
| .query() | ||
| .whereIn(relation.primaryKey, foreignValues) | ||
| .when(relation.closure, relation.closure) | ||
| .findMany(); | ||
| const map = new Map(); | ||
| results.forEach(result => map.set(result[relation.primaryKey], result)); | ||
| return models.map(model => { | ||
| model[relation.property] = map.get(model[relation.foreignKey]); | ||
| return model; | ||
| }); | ||
| } | ||
| /** | ||
| * Apply a where has relation to the query when the relation | ||
| * is a belongs to the given model. | ||
| */ | ||
| static whereHas(Model, query, relation) { | ||
| const schema = Model.schema(); | ||
| const RelationModel = relation.model(); | ||
| const primaryKey = schema.getMainPrimaryKeyName(); | ||
| const foreignKey = schema.getColumnNameByProperty(relation.foreignKey) || | ||
| schema.getColumnNameByProperty(`${String.toCamelCase(RelationModel.name)}Id`); | ||
| let whereRaw = `${Model.table()}.${foreignKey} = ${RelationModel.table()}.${primaryKey}`; | ||
| switch (RelationModel.schema().getModelDriverName()) { | ||
| case 'sqlite': | ||
| case 'postgres': | ||
| whereRaw = `"${Model.table()}"."${foreignKey}" = "${RelationModel.table()}"."${primaryKey}"`; | ||
| } | ||
| RelationModel.query() | ||
| .setDriver(query, RelationModel.table()) | ||
| .whereRaw(whereRaw) | ||
| .when(relation.closure, relation.closure); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { BelongsToManyOptions } from '#src/types'; | ||
| import type { Driver } from '#src/database/drivers/Driver'; | ||
| export declare class BelongsToManyRelation { | ||
| /** | ||
| * Get the options with defined default values. | ||
| */ | ||
| private static options; | ||
| /** | ||
| * Load a belongs to many relation. | ||
| */ | ||
| static load(model: BaseModel, relation: BelongsToManyOptions): Promise<any>; | ||
| /** | ||
| * Load all models that belongs to relation. | ||
| */ | ||
| static loadAll(models: BaseModel[], relation: BelongsToManyOptions): Promise<any[]>; | ||
| /** | ||
| * Apply a where has relation to the query when the given model | ||
| * belongs to many relations. | ||
| */ | ||
| static whereHas(Model: typeof BaseModel, query: Driver, relation: BelongsToManyOptions): void; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { String } from '@athenna/common'; | ||
| export class BelongsToManyRelation { | ||
| /** | ||
| * Get the options with defined default values. | ||
| */ | ||
| static options(relation) { | ||
| const RelationModel = relation.model(); | ||
| const PivotModel = relation.pivotModel(); | ||
| relation.pivotTable = relation.pivotTable || PivotModel.table(); | ||
| relation.relationPrimaryKey = | ||
| RelationModel.schema().getMainPrimaryKeyProperty(); | ||
| relation.relationForeignKey = `${String.toCamelCase(RelationModel.name)}Id`; | ||
| return relation; | ||
| } | ||
| /** | ||
| * Load a belongs to many relation. | ||
| */ | ||
| static async load(model, relation) { | ||
| this.options(relation); | ||
| const pivotData = await relation | ||
| .pivotModel() | ||
| .query() | ||
| .where(relation.foreignKey, model[relation.primaryKey]) | ||
| .findMany(); | ||
| const relationIds = pivotData.map(d => d[relation.relationForeignKey]); | ||
| model[relation.property] = await relation | ||
| .model() | ||
| .query() | ||
| .whereIn(relation.relationPrimaryKey, relationIds) | ||
| .when(relation.closure, relation.closure) | ||
| .findMany(); | ||
| return model; | ||
| } | ||
| /** | ||
| * Load all models that belongs to relation. | ||
| */ | ||
| static async loadAll(models, relation) { | ||
| this.options(relation); | ||
| const primaryKeys = models.map(m => m[relation.primaryKey]); | ||
| const pivotData = await relation | ||
| .pivotModel() | ||
| .query() | ||
| .whereIn(relation.foreignKey, primaryKeys) | ||
| .findMany(); | ||
| const pivotDataMap = new Map(); | ||
| const relationForeignKey = []; | ||
| pivotData.forEach(data => { | ||
| relationForeignKey.push(data[relation.relationForeignKey]); | ||
| const array = pivotDataMap.get(data[relation.foreignKey]) || []; | ||
| array.push(data[relation.relationForeignKey]); | ||
| pivotDataMap.set(data[relation.foreignKey], array); | ||
| }); | ||
| const results = await relation | ||
| .model() | ||
| .query() | ||
| .whereIn(relation.relationPrimaryKey, relationForeignKey) | ||
| .when(relation.closure, relation.closure) | ||
| .findMany(); | ||
| const map = new Map(); | ||
| results.forEach(result => map.set(result[relation.relationPrimaryKey], result)); | ||
| return models.map(model => { | ||
| const ids = pivotDataMap.get(model[relation.primaryKey]) || []; | ||
| model[relation.property] = ids | ||
| .map(id => map.get(id)) | ||
| .filter(data => data !== undefined); | ||
| return model; | ||
| }); | ||
| } | ||
| /** | ||
| * Apply a where has relation to the query when the given model | ||
| * belongs to many relations. | ||
| */ | ||
| static whereHas(Model, query, relation) { | ||
| const PivotModel = relation.pivotModel(); | ||
| const RelationModel = relation.model(); | ||
| const modelTable = Model.table(); | ||
| const pivotTable = PivotModel.table(); | ||
| const relatedTable = RelationModel.table(); | ||
| const modelPK = Model.schema().getMainPrimaryKeyName(); | ||
| const relatedPK = RelationModel.schema().getMainPrimaryKeyName(); | ||
| const pivotFK = PivotModel.schema().getColumnNameByProperty(relation.foreignKey) || | ||
| PivotModel.schema().getColumnNameByProperty(`${String.toCamelCase(Model.name)}Id`); | ||
| const pivotRK = PivotModel.schema().getColumnNameByProperty(relation.relationForeignKey) || | ||
| PivotModel.schema().getColumnNameByProperty(`${String.toCamelCase(RelationModel.name)}Id`); | ||
| let whereRaw = `${pivotTable}.${pivotFK} = ${modelTable}.${modelPK}`; | ||
| switch (PivotModel.schema().getModelDriverName()) { | ||
| case 'sqlite': | ||
| case 'postgres': | ||
| whereRaw = `"${pivotTable}"."${pivotFK}" = "${modelTable}"."${modelPK}"`; | ||
| } | ||
| PivotModel.query() | ||
| .setDriver(query, pivotTable) | ||
| .whereRaw(whereRaw) | ||
| .whereExists(innerQuery => { | ||
| let whereRaw = `${relatedTable}.${relatedPK} = ${pivotTable}.${pivotRK}`; | ||
| switch (RelationModel.schema().getModelDriverName()) { | ||
| case 'sqlite': | ||
| case 'postgres': | ||
| whereRaw = `"${relatedTable}"."${relatedPK}" = "${pivotTable}"."${pivotRK}"`; | ||
| } | ||
| RelationModel.query() | ||
| .setDriver(innerQuery, relatedTable) | ||
| .whereRaw(whereRaw) | ||
| .when(relation.closure, relation.closure); | ||
| }); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { HasManyOptions } from '#src/types'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { Driver } from '#src/database/drivers/Driver'; | ||
| export declare class HasManyRelation { | ||
| /** | ||
| * Load a has many relation. | ||
| */ | ||
| static load(model: BaseModel, relation: HasManyOptions): Promise<any>; | ||
| /** | ||
| * Load all models that has one relation. | ||
| */ | ||
| static loadAll(models: BaseModel[], relation: HasManyOptions): Promise<any[]>; | ||
| /** | ||
| * Apply a where has relation to the query when the given model | ||
| * has many of the relation. | ||
| */ | ||
| static whereHas(Model: typeof BaseModel, query: Driver, relation: HasManyOptions): void; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { String } from '@athenna/common'; | ||
| export class HasManyRelation { | ||
| /** | ||
| * Load a has many relation. | ||
| */ | ||
| static async load(model, relation) { | ||
| model[relation.property] = await relation | ||
| .model() | ||
| .query() | ||
| .where(relation.foreignKey, model[relation.primaryKey]) | ||
| .when(relation.closure, relation.closure) | ||
| .findMany(); | ||
| return model; | ||
| } | ||
| /** | ||
| * Load all models that has one relation. | ||
| */ | ||
| static async loadAll(models, relation) { | ||
| const primaryValues = models.map(model => model[relation.primaryKey]); | ||
| const results = await relation | ||
| .model() | ||
| .query() | ||
| .whereIn(relation.foreignKey, primaryValues) | ||
| .when(relation.closure, relation.closure) | ||
| .findMany(); | ||
| const map = new Map(); | ||
| results.forEach(result => { | ||
| const array = map.get(result[relation.foreignKey]) || []; | ||
| array.push(result); | ||
| map.set(result[relation.foreignKey], array); | ||
| }); | ||
| return models.map(model => { | ||
| model[relation.property] = map.get(model[relation.primaryKey]) || []; | ||
| return model; | ||
| }); | ||
| } | ||
| /** | ||
| * Apply a where has relation to the query when the given model | ||
| * has many of the relation. | ||
| */ | ||
| static whereHas(Model, query, relation) { | ||
| const schema = Model.schema(); | ||
| const RelationModel = relation.model(); | ||
| const primaryKey = schema.getMainPrimaryKeyName(); | ||
| const foreignKey = schema.getColumnNameByProperty(relation.foreignKey) || | ||
| schema.getColumnNameByProperty(`${String.toCamelCase(RelationModel.name)}Id`); | ||
| let whereRaw = `${RelationModel.table()}.${foreignKey} = ${Model.table()}.${primaryKey}`; | ||
| switch (RelationModel.schema().getModelDriverName()) { | ||
| case 'sqlite': | ||
| case 'postgres': | ||
| whereRaw = `"${RelationModel.table()}"."${foreignKey}" = "${Model.table()}"."${primaryKey}"`; | ||
| } | ||
| RelationModel.query() | ||
| .setDriver(query, RelationModel.table()) | ||
| .whereRaw(whereRaw) | ||
| .when(relation.closure, relation.closure); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { HasOneOptions } from '#src/types'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { Driver } from '#src/database/drivers/Driver'; | ||
| export declare class HasOneRelation { | ||
| /** | ||
| * Load a has one relation. | ||
| */ | ||
| static load(model: BaseModel, relation: HasOneOptions): Promise<any>; | ||
| /** | ||
| * Load all models that has one relation. | ||
| */ | ||
| static loadAll(models: BaseModel[], relation: HasOneOptions): Promise<any[]>; | ||
| /** | ||
| * Apply a where has relation to the query when the given model | ||
| * has one of the relation. | ||
| */ | ||
| static whereHas(Model: typeof BaseModel, query: Driver, relation: HasOneOptions): void; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { String } from '@athenna/common'; | ||
| export class HasOneRelation { | ||
| /** | ||
| * Load a has one relation. | ||
| */ | ||
| static async load(model, relation) { | ||
| model[relation.property] = await relation | ||
| .model() | ||
| .query() | ||
| .where(relation.foreignKey, model[relation.primaryKey]) | ||
| .when(relation.closure, relation.closure) | ||
| .find(); | ||
| return model; | ||
| } | ||
| /** | ||
| * Load all models that has one relation. | ||
| */ | ||
| static async loadAll(models, relation) { | ||
| const primaryValues = models.map(model => model[relation.primaryKey]); | ||
| const results = await relation | ||
| .model() | ||
| .query() | ||
| .whereIn(relation.foreignKey, primaryValues) | ||
| .when(relation.closure, relation.closure) | ||
| .findMany(); | ||
| const map = new Map(); | ||
| results.forEach(result => map.set(result[relation.foreignKey], result)); | ||
| return models.map(model => { | ||
| model[relation.property] = map.get(model[relation.primaryKey]); | ||
| return model; | ||
| }); | ||
| } | ||
| /** | ||
| * Apply a where has relation to the query when the given model | ||
| * has one of the relation. | ||
| */ | ||
| static whereHas(Model, query, relation) { | ||
| const schema = Model.schema(); | ||
| const RelationModel = relation.model(); | ||
| const primaryKey = schema.getMainPrimaryKeyName(); | ||
| const foreignKey = schema.getColumnNameByProperty(relation.foreignKey) || | ||
| schema.getColumnNameByProperty(`${String.toCamelCase(RelationModel.name)}Id`); | ||
| let whereRaw = `${RelationModel.table()}.${foreignKey} = ${Model.table()}.${primaryKey}`; | ||
| switch (RelationModel.schema().getModelDriverName()) { | ||
| case 'sqlite': | ||
| case 'postgres': | ||
| whereRaw = `"${RelationModel.table()}"."${foreignKey}" = "${Model.table()}"."${primaryKey}"`; | ||
| } | ||
| RelationModel.query() | ||
| .setDriver(query, RelationModel.table()) | ||
| .whereRaw(whereRaw) | ||
| .when(relation.closure, relation.closure); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { ColumnOptions, ModelColumns, ModelRelations, RelationOptions } from '#src/types'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import { Macroable } from '@athenna/common'; | ||
| import type { ModelQueryBuilder } from '#src/models/builders/ModelQueryBuilder'; | ||
| export declare class ModelSchema<M extends BaseModel = any> extends Macroable { | ||
| /** | ||
| * Save the columns defined by @Column annotation. | ||
| */ | ||
| columns: ColumnOptions[]; | ||
| /** | ||
| * Save the relations defined by \@HasOne, \@BelongsTo, | ||
| * \@HasMany and \@ManyToMany annotations. | ||
| */ | ||
| relations: RelationOptions[]; | ||
| /** | ||
| * The model class that is going to be used | ||
| * to craft the schema. | ||
| */ | ||
| private Model; | ||
| constructor(model: any); | ||
| /** | ||
| * Sync the database creating migrations | ||
| * or schemas in the database connection. | ||
| */ | ||
| sync(): Promise<void>; | ||
| /** | ||
| * Get the model name set for the schema. | ||
| */ | ||
| getModelName(): string; | ||
| /** | ||
| * Get the model table set for the schema. | ||
| */ | ||
| getModelTable(): string; | ||
| /** | ||
| * Get the model driver name. | ||
| */ | ||
| getModelDriverName(): any; | ||
| /** | ||
| * Get the model driver. | ||
| */ | ||
| getModelDriver(): import("../../database/drivers/MongoDriver.js").MongoDriver | import("../../database/drivers/MySqlDriver.js").MySqlDriver | import("../../database/drivers/SqliteDriver.js").SqliteDriver | import("../../database/drivers/PostgresDriver.js").PostgresDriver | typeof import("../../database/drivers/FakeDriver.js").FakeDriver; | ||
| /** | ||
| * Get the model connection name. | ||
| */ | ||
| getModelConnection(): string; | ||
| /** | ||
| * Get the column options of the main primary key. | ||
| */ | ||
| getMainPrimaryKey(): ColumnOptions; | ||
| /** | ||
| * Get the main primary key column name. | ||
| */ | ||
| getMainPrimaryKeyName(): string; | ||
| /** | ||
| * Get the main primary key property. | ||
| */ | ||
| getMainPrimaryKeyProperty(): string; | ||
| /** | ||
| * Convert an object using properties to database use | ||
| * column names. | ||
| */ | ||
| propertiesToColumnNames(data: Partial<M> | ModelColumns<M>, options?: { | ||
| attributes?: Record<string, any>; | ||
| cleanPersist?: boolean; | ||
| }): {}; | ||
| /** | ||
| * Get the column options where column has isCreateDate | ||
| * as true. | ||
| */ | ||
| getCreatedAtColumn(): ColumnOptions; | ||
| /** | ||
| * Get the column options where column has isUpdateDate | ||
| * as true. | ||
| */ | ||
| getUpdatedAtColumn(): ColumnOptions; | ||
| /** | ||
| * Get the column options where column has isDeleteDate | ||
| * as true. | ||
| */ | ||
| getDeletedAtColumn(): ColumnOptions; | ||
| /** | ||
| * Get all column properties as an array of string. | ||
| */ | ||
| getAllColumnProperties(): string[]; | ||
| /** | ||
| * Get all column names as an array of string. | ||
| */ | ||
| getAllColumnNames(): string[]; | ||
| /** | ||
| * Get all columns where unique option is true. | ||
| */ | ||
| getAllUniqueColumns(): ColumnOptions[]; | ||
| /** | ||
| * Get all columns where hidden option is true. | ||
| */ | ||
| getAllHiddenColumns(): ColumnOptions[]; | ||
| /** | ||
| * Get all columns where nullable option is false. | ||
| */ | ||
| getAllNotNullableColumns(): ColumnOptions[]; | ||
| /** | ||
| * Validate that model has createdAt and updatedAt | ||
| * column defined. | ||
| */ | ||
| hasTimestamps(): boolean; | ||
| /** | ||
| * Get the column options by the column database name. | ||
| */ | ||
| getColumnByName(column: string | ModelColumns<M>): ColumnOptions; | ||
| /** | ||
| * Get the column options by the column database name. | ||
| * | ||
| * If property cannot be found, the column name will be used. | ||
| */ | ||
| getPropertyByColumnName(column: string | ModelColumns<M>): string; | ||
| /** | ||
| * Get all the properties names by an array of column database names. | ||
| * | ||
| * If property cannot be found, the column name will be used. | ||
| */ | ||
| getPropertiesByColumnNames(columns: string[] | ModelColumns<M>[]): string[]; | ||
| /** | ||
| * Get the column options by the model class property. | ||
| */ | ||
| getColumnByProperty(property: string | ModelColumns<M>): ColumnOptions; | ||
| /** | ||
| * Get the column name by the model class property. | ||
| * | ||
| * If the column name cannot be found, the property will be used. | ||
| */ | ||
| getColumnNameByProperty(property: string | ModelColumns<M>): string; | ||
| /** | ||
| * Get all the columns names by an array of model class properties. | ||
| * | ||
| * If the column name cannot be found, the property will be used. | ||
| */ | ||
| getColumnNamesByProperties(properties: string[] | ModelColumns<M>[]): string[]; | ||
| /** | ||
| * Get the relation by the class property name. | ||
| */ | ||
| getRelationByProperty(property: string | ModelColumns<M>): RelationOptions; | ||
| /** | ||
| * Return the relation options only from relations | ||
| * that are included. | ||
| */ | ||
| getIncludedRelations(): RelationOptions[]; | ||
| /** | ||
| * Return the relation properties. | ||
| */ | ||
| getRelationProperties(): string[]; | ||
| /** | ||
| * Include a relation by setting the isIncluded | ||
| * option to true. | ||
| */ | ||
| includeRelation(property: string | ModelRelations<M>, closure?: (query: ModelQueryBuilder) => any): RelationOptions; | ||
| /** | ||
| * Include a relation by setting the isWhereHasIncluded | ||
| * option to true. | ||
| */ | ||
| includeWhereHasRelation(property: string | ModelRelations<M>, closure?: (query: ModelQueryBuilder) => any): RelationOptions; | ||
| /** | ||
| * Created nested relationships closure to | ||
| * load relationship's relationships | ||
| */ | ||
| private createdNestedRelationClosure; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Database } from '#src/facades/Database'; | ||
| import { Annotation } from '#src/helpers/Annotation'; | ||
| import { Json, Options, Macroable } from '@athenna/common'; | ||
| import { NotImplementedRelationException } from '#src/exceptions/NotImplementedRelationException'; | ||
| export class ModelSchema extends Macroable { | ||
| constructor(model) { | ||
| super(); | ||
| this.Model = model; | ||
| this.columns = Json.copy(Annotation.getColumnsMeta(model)); | ||
| this.relations = Json.copy(Annotation.getRelationsMeta(model)); | ||
| } | ||
| /** | ||
| * Sync the database creating migrations | ||
| * or schemas in the database connection. | ||
| */ | ||
| async sync() { | ||
| await this.getModelDriver().sync(this); | ||
| } | ||
| /** | ||
| * Get the model name set for the schema. | ||
| */ | ||
| getModelName() { | ||
| return this.Model.name; | ||
| } | ||
| /** | ||
| * Get the model table set for the schema. | ||
| */ | ||
| getModelTable() { | ||
| return this.Model.table(); | ||
| } | ||
| /** | ||
| * Get the model driver name. | ||
| */ | ||
| getModelDriverName() { | ||
| const connection = this.getModelConnection(); | ||
| return Config.get(`database.connections.${connection}.driver`); | ||
| } | ||
| /** | ||
| * Get the model driver. | ||
| */ | ||
| getModelDriver() { | ||
| const connection = this.getModelConnection(); | ||
| return Database.connection(connection).driver; | ||
| } | ||
| /** | ||
| * Get the model connection name. | ||
| */ | ||
| getModelConnection() { | ||
| const connection = this.Model.connection(); | ||
| if (connection === 'default') { | ||
| return Config.get('database.default'); | ||
| } | ||
| return connection; | ||
| } | ||
| /** | ||
| * Get the column options of the main primary key. | ||
| */ | ||
| getMainPrimaryKey() { | ||
| let options = this.columns.find(c => c.isMainPrimary); | ||
| if (!options) { | ||
| options = this.columns.find(c => c.name === 'id'); | ||
| if (options) { | ||
| if (!options.hasSetName && this.getModelDriverName() === 'mongo') { | ||
| options.name = '_id'; | ||
| } | ||
| } | ||
| } | ||
| if (!options) { | ||
| options = this.columns.find(c => c.name === '_id'); | ||
| } | ||
| return options; | ||
| } | ||
| /** | ||
| * Get the main primary key column name. | ||
| */ | ||
| getMainPrimaryKeyName() { | ||
| const options = this.getMainPrimaryKey(); | ||
| return options?.name || 'id'; | ||
| } | ||
| /** | ||
| * Get the main primary key property. | ||
| */ | ||
| getMainPrimaryKeyProperty() { | ||
| const options = this.getMainPrimaryKey(); | ||
| return options?.property || 'id'; | ||
| } | ||
| /** | ||
| * Convert an object using properties to database use | ||
| * column names. | ||
| */ | ||
| propertiesToColumnNames(data, options = {}) { | ||
| options = Options.create(options, { | ||
| attributes: {}, | ||
| cleanPersist: false | ||
| }); | ||
| const parsed = {}; | ||
| Object.keys(data).forEach(key => { | ||
| const column = this.getColumnByProperty(key) || { | ||
| name: key, | ||
| persist: false | ||
| }; | ||
| if (!column.persist && options.cleanPersist) { | ||
| return; | ||
| } | ||
| if (data[key] === undefined) { | ||
| return; | ||
| } | ||
| parsed[column.name] = data[key]; | ||
| }); | ||
| Object.keys(options.attributes).forEach(key => { | ||
| const column = this.getColumnByProperty(key) || { | ||
| name: key, | ||
| persist: false | ||
| }; | ||
| if (parsed[column.name] !== undefined) { | ||
| return; | ||
| } | ||
| parsed[column.name] = options.attributes[key]; | ||
| }); | ||
| return parsed; | ||
| } | ||
| /** | ||
| * Get the column options where column has isCreateDate | ||
| * as true. | ||
| */ | ||
| getCreatedAtColumn() { | ||
| return this.columns.find(c => c.isCreateDate); | ||
| } | ||
| /** | ||
| * Get the column options where column has isUpdateDate | ||
| * as true. | ||
| */ | ||
| getUpdatedAtColumn() { | ||
| return this.columns.find(c => c.isUpdateDate); | ||
| } | ||
| /** | ||
| * Get the column options where column has isDeleteDate | ||
| * as true. | ||
| */ | ||
| getDeletedAtColumn() { | ||
| return this.columns.find(c => c.isDeleteDate); | ||
| } | ||
| /** | ||
| * Get all column properties as an array of string. | ||
| */ | ||
| getAllColumnProperties() { | ||
| return this.columns.map(column => column.property); | ||
| } | ||
| /** | ||
| * Get all column names as an array of string. | ||
| */ | ||
| getAllColumnNames() { | ||
| return this.columns.map(column => column.name); | ||
| } | ||
| /** | ||
| * Get all columns where unique option is true. | ||
| */ | ||
| getAllUniqueColumns() { | ||
| return this.columns.filter(column => column.isUnique); | ||
| } | ||
| /** | ||
| * Get all columns where hidden option is true. | ||
| */ | ||
| getAllHiddenColumns() { | ||
| return this.columns.filter(column => column.isHidden); | ||
| } | ||
| /** | ||
| * Get all columns where nullable option is false. | ||
| */ | ||
| getAllNotNullableColumns() { | ||
| return this.columns.filter(column => !column.isNullable); | ||
| } | ||
| /** | ||
| * Validate that model has createdAt and updatedAt | ||
| * column defined. | ||
| */ | ||
| hasTimestamps() { | ||
| return !!this.getCreatedAtColumn() && !!this.getUpdatedAtColumn(); | ||
| } | ||
| /** | ||
| * Get the column options by the column database name. | ||
| */ | ||
| getColumnByName(column) { | ||
| return this.columns.find(c => c.name === column); | ||
| } | ||
| /** | ||
| * Get the column options by the column database name. | ||
| * | ||
| * If property cannot be found, the column name will be used. | ||
| */ | ||
| getPropertyByColumnName(column) { | ||
| return this.getColumnByName(column)?.property || column; | ||
| } | ||
| /** | ||
| * Get all the properties names by an array of column database names. | ||
| * | ||
| * If property cannot be found, the column name will be used. | ||
| */ | ||
| getPropertiesByColumnNames(columns) { | ||
| return columns.map(column => this.getPropertyByColumnName(column)); | ||
| } | ||
| /** | ||
| * Get the column options by the model class property. | ||
| */ | ||
| getColumnByProperty(property) { | ||
| return this.columns.find(c => c.property === property); | ||
| } | ||
| /** | ||
| * Get the column name by the model class property. | ||
| * | ||
| * If the column name cannot be found, the property will be used. | ||
| */ | ||
| getColumnNameByProperty(property) { | ||
| return this.getColumnByProperty(property)?.name || property; | ||
| } | ||
| /** | ||
| * Get all the columns names by an array of model class properties. | ||
| * | ||
| * If the column name cannot be found, the property will be used. | ||
| */ | ||
| getColumnNamesByProperties(properties) { | ||
| return properties.map(property => this.getColumnNameByProperty(property)); | ||
| } | ||
| /** | ||
| * Get the relation by the class property name. | ||
| */ | ||
| getRelationByProperty(property) { | ||
| return this.relations.find(c => c.property === property); | ||
| } | ||
| /** | ||
| * Return the relation options only from relations | ||
| * that are included. | ||
| */ | ||
| getIncludedRelations() { | ||
| return this.relations.filter(r => r.isIncluded || r.isWhereHasIncluded); | ||
| } | ||
| /** | ||
| * Return the relation properties. | ||
| */ | ||
| getRelationProperties() { | ||
| return this.relations.map(r => r.property); | ||
| } | ||
| /** | ||
| * Include a relation by setting the isIncluded | ||
| * option to true. | ||
| */ | ||
| includeRelation(property, closure) { | ||
| const model = this.Model.name; | ||
| if (property.includes('.')) { | ||
| const [first, ...rest] = property.split('.'); | ||
| property = first; | ||
| closure = this.createdNestedRelationClosure(rest); | ||
| } | ||
| const options = this.getRelationByProperty(property); | ||
| if (!options) { | ||
| throw new NotImplementedRelationException(property, model, this.relations.map(r => r.property).join(', ')); | ||
| } | ||
| const i = this.relations.indexOf(options); | ||
| options.isIncluded = true; | ||
| options.closure = closure; | ||
| this.relations[i] = options; | ||
| return options; | ||
| } | ||
| /** | ||
| * Include a relation by setting the isWhereHasIncluded | ||
| * option to true. | ||
| */ | ||
| includeWhereHasRelation(property, closure) { | ||
| const model = this.Model.name; | ||
| if (property.includes('.')) { | ||
| const [first, ...rest] = property.split('.'); | ||
| property = first; | ||
| closure = this.createdNestedRelationClosure(rest); | ||
| } | ||
| const options = this.getRelationByProperty(property); | ||
| if (!options) { | ||
| throw new NotImplementedRelationException(property, model, this.relations.map(r => r.property).join(', ')); | ||
| } | ||
| const i = this.relations.indexOf(options); | ||
| options.isWhereHasIncluded = true; | ||
| options.closure = closure; | ||
| this.relations[i] = options; | ||
| return options; | ||
| } | ||
| /** | ||
| * Created nested relationships closure to | ||
| * load relationship's relationships | ||
| */ | ||
| createdNestedRelationClosure(relationships) { | ||
| if (relationships.length === 1) { | ||
| return (query) => query.with(relationships[0]); | ||
| } | ||
| const [first, ...rest] = relationships; | ||
| const closure = this.createdNestedRelationClosure(rest); | ||
| return (query) => query.with(first, closure); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { ServiceProvider } from '@athenna/ioc'; | ||
| export declare class DatabaseProvider extends ServiceProvider { | ||
| register(): Promise<void>; | ||
| shutdown(): Promise<void>; | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import { Module } from '@athenna/common'; | ||
| import { ServiceProvider } from '@athenna/ioc'; | ||
| import { DatabaseImpl } from '#src/database/DatabaseImpl'; | ||
| export class DatabaseProvider extends ServiceProvider { | ||
| async register() { | ||
| this.container.instance('athennaDbOpts', undefined); | ||
| this.container.transient('Athenna/Core/Database', DatabaseImpl); | ||
| const paths = Config.get('rc.models', []); | ||
| const promises = paths.map(path => { | ||
| return Module.resolve(path, Config.get('rc.parentURL')).then(Model => { | ||
| this.container.transient(`App/Models/${Model.name}`, Model); | ||
| if (!Model.sync()) { | ||
| return; | ||
| } | ||
| return Model.schema().sync(); | ||
| }); | ||
| }); | ||
| await Promise.all(promises); | ||
| } | ||
| async shutdown() { | ||
| const database = this.container.use('Athenna/Core/Database'); | ||
| if (!database) { | ||
| return; | ||
| } | ||
| await database.closeAll(); | ||
| } | ||
| } |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { ColumnType } from '#src/types/columns/ColumnType'; | ||
| export type ColumnOptions = { | ||
| /** | ||
| * The property name in class of the column. | ||
| * | ||
| * @readonly | ||
| * @default key | ||
| */ | ||
| property?: string; | ||
| /** | ||
| * The column name in database. The default | ||
| * value of this property will be the name | ||
| * of the class property as camelCase. | ||
| * | ||
| * @default String.toCamelCase(key) | ||
| */ | ||
| name?: string; | ||
| /** | ||
| * Holds if the user has set the name property | ||
| * in @Column or not. | ||
| */ | ||
| hasSetName?: boolean; | ||
| /** | ||
| * The column type in database. This value | ||
| * only matters when you are using MongoDB | ||
| * or when you want to synchronize you model | ||
| * with database FOR DEVELOPMENT purposes only. | ||
| * | ||
| * @default undefined | ||
| */ | ||
| type?: ColumnType; | ||
| /** | ||
| * The column length in database. This value only | ||
| * matters when you a want to synchronize your | ||
| * model with database FOR DEVELOPMENT purposes only. | ||
| * | ||
| * @default undefined | ||
| */ | ||
| length?: number; | ||
| /** | ||
| * Set the default value for the column before | ||
| * running your model `create()`, `createMany()`, | ||
| * `update()` and `createOrUpdate()` methods. | ||
| * | ||
| * This property doesn't change the behavior in | ||
| * your database, but only while running the above | ||
| * methods. | ||
| * | ||
| * @default null | ||
| */ | ||
| defaultTo?: any; | ||
| /** | ||
| * Set if the column is a primary key. | ||
| * | ||
| * @default false | ||
| */ | ||
| isPrimary?: boolean; | ||
| /** | ||
| * Set if the field should be hidden when | ||
| * executing the `toJSON()` method of the model. | ||
| * | ||
| * @default false | ||
| */ | ||
| isHidden?: boolean; | ||
| /** | ||
| * Set if the column is unique in database. | ||
| * | ||
| * @default false | ||
| */ | ||
| isUnique?: boolean; | ||
| /** | ||
| * Set if the column is nullable in database. | ||
| * | ||
| * @default true | ||
| */ | ||
| isNullable?: boolean; | ||
| /** | ||
| * Set if the column is an index in database. | ||
| * | ||
| * @default false | ||
| */ | ||
| isIndex?: boolean; | ||
| /** | ||
| * Set if the column is sparse in database. | ||
| * | ||
| * @default false | ||
| */ | ||
| isSparse?: boolean; | ||
| /** | ||
| * Set if the column should be persisted in database | ||
| * when executing operation like create or update. | ||
| * | ||
| * If set as `false`, Athenna will remove this column | ||
| * from this kind of operation, but it will still be | ||
| * available in operations like `find` and `findMany`. | ||
| * | ||
| * To also remove from listing operations, set isHidden | ||
| * as `true`. | ||
| * | ||
| * @default true | ||
| */ | ||
| persist?: boolean; | ||
| /** | ||
| * Set if this column is the main primary key that | ||
| * should be used when performing create queries to | ||
| * database. | ||
| * | ||
| * Your class can only have one column option with | ||
| * isMainPrimary set as true. If you set isMainPrimary | ||
| * as true, Athenna will set isPrimary as true by default. | ||
| * | ||
| * @default false | ||
| */ | ||
| isMainPrimary?: boolean; | ||
| /** | ||
| * Set if the column is createdAt field. | ||
| * Columns with `isCreateDate` as `true` | ||
| * will automatically be set with `new Date()` | ||
| * value when creating your model. | ||
| * | ||
| * The `new Date()` value will only be set | ||
| * when your column doesn't have `defaultTo` | ||
| * value set and also when the field is not | ||
| * present when calling any method that creates | ||
| * the model in database like `create()`. | ||
| * | ||
| * @default false | ||
| */ | ||
| isCreateDate?: boolean; | ||
| /** | ||
| * Set if the column is updatedAt field. | ||
| * Columns with `isUpdateDate` as `true` | ||
| * will automatically be set with `new Date()` | ||
| * value when updating your model. | ||
| * | ||
| * The `new Date()` value will only be set | ||
| * when your column doesn't have `defaultTo` | ||
| * value set and also when the field is not | ||
| * present when calling any method that updates | ||
| * the model in database like `update()`. | ||
| * | ||
| * @default false | ||
| */ | ||
| isUpdateDate?: boolean; | ||
| /** | ||
| * Set if the column is deletedAt field. | ||
| * By default, if you define add field with | ||
| * `isDeleteDate` as `true`, it will automatically | ||
| * turn on soft delete for your model, this means | ||
| * that if this column is not null, it will be | ||
| * considered a deleted value, not being retrieved | ||
| * when calling methods like `find()`. | ||
| * | ||
| * It will also automatically set `new Date()` | ||
| * value to the column when deleting your model. | ||
| * | ||
| * The `new Date()` value will only be set | ||
| * when your column doesn't have `defaultTo` | ||
| * value set and also when the field is not | ||
| * present when calling `delete()` method. | ||
| * | ||
| * @default false | ||
| */ | ||
| isDeleteDate?: boolean; | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { Schema } from 'mongoose'; | ||
| export type ColumnType = 'string' | 'uuid' | 'UUID' | 'enum' | 'integer' | 'float' | 'double' | 'numeric' | 'decimal' | 'json' | 'jsonb' | 'date' | 'datetime' | 'timestamp' | typeof String | typeof Number | typeof Date | typeof Buffer | typeof Boolean | typeof Schema.Types.UUID | typeof Schema.Types.BigInt | typeof Schema.Types.Mixed | typeof Schema.Types.ObjectId | typeof Array<any> | typeof Schema.Types.Decimal128 | typeof Map<any, any> | typeof Schema | typeof BigInt; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| export type ColumnKeys<T> = { | ||
| [K in keyof T]: T[K] extends BaseModel | BaseModel[] ? never : K; | ||
| }[keyof Omit<T, 'save' | 'fresh' | 'refresh' | 'dirty' | 'delete' | 'restore' | 'isDirty' | 'isTrashed' | 'isPersisted' | 'setOriginal' | 'load' | 'toJSON'>]; | ||
| export type ModelColumns<T> = Extract<ColumnKeys<T>, string>; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export type ConnectionOptions = { | ||
| /** | ||
| * Force the connection to be created even if the | ||
| * connection is already opened. This option is | ||
| * useful to create a connection from scratch, meaning | ||
| * that your driver will not use the default one. This | ||
| * also means that is your responsibility to close this | ||
| * connection. | ||
| * | ||
| * @default false | ||
| */ | ||
| force?: boolean; | ||
| /** | ||
| * Save your connection in the ConnectionFactory class. | ||
| * If this is true, all the drivers will have a shared | ||
| * connection to use. | ||
| * | ||
| * @default true | ||
| */ | ||
| saveOnFactory?: boolean; | ||
| /** | ||
| * Since we are using the constructor method to create | ||
| * the connection, it could create the connection when | ||
| * we don't really want to. To avoid creating the | ||
| * connection is certain scenarios where you want to | ||
| * manipulate the driver client, set this option to `false`. | ||
| * | ||
| * @default true | ||
| */ | ||
| connect?: boolean; | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export type Connections = 'fake' | 'mongo' | 'mysql' | 'sqlite' | 'postgres' | string; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export type Direction = 'asc' | 'desc' | 'ASC' | 'DESC'; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { Driver } from '#src/database/drivers/Driver'; | ||
| export type DriverKey = { | ||
| Driver: new (...args: any[]) => Driver; | ||
| client?: any; | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export * from '#src/types/Direction'; | ||
| export * from '#src/types/Operations'; | ||
| export * from '#src/types/Connections'; | ||
| export * from '#src/types/ConnectionOptions'; | ||
| export * from '#src/types/columns/ColumnType'; | ||
| export * from '#src/types/relations/Relation'; | ||
| export * from '#src/types/columns/ModelColumns'; | ||
| export * from '#src/types/columns/ColumnOptions'; | ||
| export * from '#src/types/relations/HasOneOptions'; | ||
| export * from '#src/types/relations/HasManyOptions'; | ||
| export * from '#src/types/relations/BelongsToOptions'; | ||
| export * from '#src/types/relations/BelongsToManyOptions'; | ||
| export * from '#src/types/relations/RelationOptions'; | ||
| export * from '#src/types/relations/ModelRelations'; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export * from '#src/types/Direction'; | ||
| export * from '#src/types/Operations'; | ||
| export * from '#src/types/Connections'; | ||
| export * from '#src/types/ConnectionOptions'; | ||
| export * from '#src/types/columns/ColumnType'; | ||
| export * from '#src/types/relations/Relation'; | ||
| export * from '#src/types/columns/ModelColumns'; | ||
| export * from '#src/types/columns/ColumnOptions'; | ||
| export * from '#src/types/relations/HasOneOptions'; | ||
| export * from '#src/types/relations/HasManyOptions'; | ||
| export * from '#src/types/relations/BelongsToOptions'; | ||
| export * from '#src/types/relations/BelongsToManyOptions'; | ||
| export * from '#src/types/relations/RelationOptions'; | ||
| export * from '#src/types/relations/ModelRelations'; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export type Operations = '=' | '>' | '>=' | '<' | '<=' | '<>' | 'like' | 'ilike'; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { ModelColumns } from '#src/types'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { ModelQueryBuilder } from '#src/models/builders/ModelQueryBuilder'; | ||
| export type BelongsToManyOptions<T extends BaseModel = any, R extends BaseModel = any, P extends BaseModel = any> = { | ||
| /** | ||
| * The relation option type. | ||
| * | ||
| * @readonly | ||
| * @default 'belongsToMany' | ||
| */ | ||
| type?: 'belongsToMany'; | ||
| /** | ||
| * The closure that should be executed while | ||
| * querying the relation data from database. | ||
| * | ||
| * @default undefined | ||
| */ | ||
| closure?: (query: ModelQueryBuilder<R>) => any; | ||
| /** | ||
| * The property name in class of the relation. | ||
| * | ||
| * @readonly | ||
| * @default key | ||
| */ | ||
| property?: ModelColumns<T>; | ||
| /** | ||
| * The relation model that is being referenced as | ||
| * a closure to protect models definition from import | ||
| * issues. | ||
| * | ||
| * @readonly | ||
| */ | ||
| model?: () => typeof BaseModel; | ||
| /** | ||
| * The pivot model that will be used to save the | ||
| * relations between main model and relation model. | ||
| * | ||
| * @readonly | ||
| */ | ||
| pivotModel?: () => typeof BaseModel; | ||
| /** | ||
| * Set if the model will be included when fetching | ||
| * data. | ||
| * If this option is true, you don't need to call | ||
| * methods like `with()` to eager load your relation. | ||
| * | ||
| * @default false | ||
| */ | ||
| isIncluded?: boolean; | ||
| /** | ||
| * Set if the model will be included when fetching | ||
| * data. | ||
| * If this option is true, you don't need to call | ||
| * methods like `whereHas()` to eager load your relation. | ||
| * | ||
| * @default false | ||
| */ | ||
| isWhereHasIncluded?: boolean; | ||
| /** | ||
| * The primary key is always the primary key | ||
| * of the main model. | ||
| * | ||
| * @default Model.schema().getMainPrimaryKey() | ||
| */ | ||
| primaryKey?: ModelColumns<T>; | ||
| /** | ||
| * The foreign key is the camelCase in singular | ||
| * representation of the main model table name with | ||
| * 'Id' in the end. The foreign key will always | ||
| * be defined inside the pivot model. | ||
| * | ||
| * @default `${String.toCamelCase(Model.name)}Id` | ||
| */ | ||
| foreignKey?: ModelColumns<P>; | ||
| /** | ||
| * The pivot table is always the merge of main model | ||
| * table name with relation model table name. | ||
| * | ||
| * @default PivotModel.table() | ||
| */ | ||
| pivotTable?: string; | ||
| /** | ||
| * The relation primary key is always the primary key | ||
| * of the relation model. | ||
| * | ||
| * @default Relation.schema().getMainPrimaryKeyName() | ||
| */ | ||
| relationPrimaryKey?: ModelColumns<R>; | ||
| /** | ||
| * The relation foreign key is the camelCase in singular | ||
| * representation of the relation model name with | ||
| * an 'Id' at the end. The relation foreign key will always | ||
| * be defined inside the pivot model. | ||
| * | ||
| * @default `${String.toCamelCase(Relation.name)}Id` | ||
| */ | ||
| relationForeignKey?: ModelColumns<P>; | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { ModelColumns } from '#src/types'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { ModelQueryBuilder } from 'src/models/builders/ModelQueryBuilder.js'; | ||
| export type BelongsToOptions<T extends BaseModel = any, R extends BaseModel = any> = { | ||
| /** | ||
| * The relation option type. | ||
| * | ||
| * @readonly | ||
| * @default 'belongsTo' | ||
| */ | ||
| type?: 'belongsTo'; | ||
| /** | ||
| * The closure that should be executed while | ||
| * querying the relation data from database. | ||
| * | ||
| * @default undefined | ||
| */ | ||
| closure?: (query: ModelQueryBuilder<R>) => any; | ||
| /** | ||
| * The property name in class of the relation. | ||
| * | ||
| * @readonly | ||
| * @default key | ||
| */ | ||
| property?: ModelColumns<T>; | ||
| /** | ||
| * The relation model that is being referenced as | ||
| * a closure to protect models definition from import | ||
| * issues. | ||
| * | ||
| * @readonly | ||
| */ | ||
| model?: () => typeof BaseModel; | ||
| /** | ||
| * Set if the model will be included when fetching | ||
| * data. | ||
| * If this option is true, you don't need to call | ||
| * methods like `with()` to eager load your relation. | ||
| * | ||
| * @default false | ||
| */ | ||
| isIncluded?: boolean; | ||
| /** | ||
| * Set if the model will be included when fetching | ||
| * data. | ||
| * If this option is true, you don't need to call | ||
| * methods like `whereHas()` to eager load your relation. | ||
| * | ||
| * @default false | ||
| */ | ||
| isWhereHasIncluded?: boolean; | ||
| /** | ||
| * The primary key is always the primary key | ||
| * of the relation model. | ||
| * | ||
| * @default RelationModel.schema().getMainPrimaryKey() | ||
| */ | ||
| primaryKey?: ModelColumns<R>; | ||
| /** | ||
| * The foreign key is the camelCase representation | ||
| * of the relation model name with an 'Id' at the end. | ||
| * The foreign key needs to be defined in the main model. | ||
| * | ||
| * @default `${String.toCamelCase(RelationModel.name)}Id` | ||
| */ | ||
| foreignKey?: ModelColumns<T>; | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { ModelColumns } from '#src/types'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { ModelQueryBuilder } from 'src/models/builders/ModelQueryBuilder.js'; | ||
| export type HasManyOptions<T extends BaseModel = any, R extends BaseModel = any> = { | ||
| /** | ||
| * The relation option type. | ||
| * | ||
| * @readonly | ||
| * @default 'hasMany' | ||
| */ | ||
| type?: 'hasMany'; | ||
| /** | ||
| * The closure that should be executed while | ||
| * querying the relation data from database. | ||
| * | ||
| * @default undefined | ||
| */ | ||
| closure?: (query: ModelQueryBuilder<R>) => any; | ||
| /** | ||
| * The property name in class of the relation. | ||
| * | ||
| * @readonly | ||
| * @default key | ||
| */ | ||
| property?: string; | ||
| /** | ||
| * The relation model that is being referenced as | ||
| * a closure to protect models definition from import | ||
| * issues. | ||
| * | ||
| * @readonly | ||
| */ | ||
| model?: () => typeof BaseModel; | ||
| /** | ||
| * Set if the model will be included when fetching | ||
| * data. | ||
| * If this option is true, you don't need to call | ||
| * methods like `with()` to eager load your relation. | ||
| * | ||
| * @default false | ||
| */ | ||
| isIncluded?: boolean; | ||
| /** | ||
| * Set if the model will be included when fetching | ||
| * data. | ||
| * If this option is true, you don't need to call | ||
| * methods like `whereHas()` to eager load your relation. | ||
| * | ||
| * @default false | ||
| */ | ||
| isWhereHasIncluded?: boolean; | ||
| /** | ||
| * The primary key is always the primary key | ||
| * of the main model. | ||
| * | ||
| * @default Model.schema().getMainPrimaryKey() | ||
| */ | ||
| primaryKey?: ModelColumns<T>; | ||
| /** | ||
| * The foreign key is the camelCase representation | ||
| * of the main model name with an 'Id' at the end. | ||
| * | ||
| * @default `${String.toCamelCase(Model.name)}Id` | ||
| */ | ||
| foreignKey?: ModelColumns<R>; | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { ModelColumns } from '#src/types'; | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| import type { ModelQueryBuilder } from '#src/models/builders/ModelQueryBuilder'; | ||
| export type HasOneOptions<T extends BaseModel = any, R extends BaseModel = any> = { | ||
| /** | ||
| * The relation option type. | ||
| * | ||
| * @readonly | ||
| * @default 'hasOne' | ||
| */ | ||
| type?: 'hasOne'; | ||
| /** | ||
| * The closure that should be executed while | ||
| * querying the relation data from database. | ||
| * | ||
| * @default undefined | ||
| */ | ||
| closure?: (query: ModelQueryBuilder<R>) => any; | ||
| /** | ||
| * The property name in class of the relation. | ||
| * | ||
| * @readonly | ||
| * @default key | ||
| */ | ||
| property?: ModelColumns<T>; | ||
| /** | ||
| * The relation model that is being referenced as | ||
| * a closure to protect models definition from import | ||
| * issues. | ||
| * | ||
| * @readonly | ||
| */ | ||
| model?: () => typeof BaseModel; | ||
| /** | ||
| * Set if the model will be included when fetching | ||
| * data. | ||
| * If this option is true, you don't need to call | ||
| * methods like `with()` to eager load your relation. | ||
| * | ||
| * @default false | ||
| */ | ||
| isIncluded?: boolean; | ||
| /** | ||
| * Set if the model will be included when fetching | ||
| * data. | ||
| * If this option is true, you don't need to call | ||
| * methods like `whereHas()` to eager load your relation. | ||
| * | ||
| * @default false | ||
| */ | ||
| isWhereHasIncluded?: boolean; | ||
| /** | ||
| * The primary key is always the primary key | ||
| * of the main model. | ||
| * | ||
| * @default Model.schema().getMainPrimaryKey() | ||
| */ | ||
| primaryKey?: ModelColumns<T>; | ||
| /** | ||
| * The foreign key is the camelCase representation | ||
| * of the main model name with an 'Id' at the end. | ||
| * | ||
| * @default `${String.toCamelCase(Model.name)}Id` | ||
| */ | ||
| foreignKey?: ModelColumns<R>; | ||
| }; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| export type RelationKeys<T> = { | ||
| [K in keyof T]: T[K] extends BaseModel | BaseModel[] ? K : never; | ||
| }[keyof T]; | ||
| export type ModelRelations<T> = Extract<RelationKeys<T>, string>; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { BaseModel } from '#src/models/BaseModel'; | ||
| export type Relation<M extends BaseModel | BaseModel[]> = M; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| import type { HasOneOptions } from '#src/types/relations/HasOneOptions'; | ||
| import type { HasManyOptions } from '#src/types/relations/HasManyOptions'; | ||
| import type { BelongsToOptions } from '#src/types/relations/BelongsToOptions'; | ||
| import type { BelongsToManyOptions } from '#src/types/relations/BelongsToManyOptions'; | ||
| export type RelationOptions = HasOneOptions | HasManyOptions | BelongsToOptions | BelongsToManyOptions; |
| /** | ||
| * @athenna/database | ||
| * | ||
| * (c) João Lenon <lenon@athenna.io> | ||
| * | ||
| * For the full copyright and license information, please view the LICENSE | ||
| * file that was distributed with this source code. | ||
| */ | ||
| export {}; |
+1
-1
| { | ||
| "name": "@athenna/database", | ||
| "version": "5.36.0", | ||
| "version": "5.37.0", | ||
| "description": "The Athenna database handler for SQL/NoSQL.", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
540735
1606%170
750%16665
6236.5%19
1800%