diff --git a/configurer/index.ts b/configurer/index.ts index 4e71e1f..3fc5c09 100644 --- a/configurer/index.ts +++ b/configurer/index.ts @@ -42,10 +42,19 @@ export default class DatabaseConfigurer extends BaseConfigurer { 'make:migration', '@athenna/database/commands/MakeMigrationCommand' ) + .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 diff --git a/package-lock.json b/package-lock.json index 6e6cf2e..c194e20 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@athenna/database", - "version": "4.42.0", + "version": "4.43.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@athenna/database", - "version": "4.42.0", + "version": "4.43.0", "license": "MIT", "dependencies": { "@faker-js/faker": "^8.4.0", diff --git a/package.json b/package.json index eaa3897..8f969d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@athenna/database", - "version": "4.42.0", + "version": "4.43.0", "description": "The Athenna database handler for SQL/NoSQL.", "license": "MIT", "author": "João Lenon ", @@ -50,7 +50,9 @@ "./package": "./package.json", "./package.json": "./package.json", "./testing/plugins": "./src/testing/plugins/index.js", + "./commands/DbFreshCommand": "./src/commands/DbFreshCommand.js", "./commands/DbSeedCommand": "./src/commands/DbSeedCommand.js", + "./commands/DbWipeCommand": "./src/commands/DbWipeCommand.js", "./commands/MakeMigrationCommand": "./src/commands/MakeMigrationCommand.js", "./commands/MakeModelCommand": "./src/commands/MakeModelCommand.js", "./commands/MakeSeederCommand": "./src/commands/MakeSeederCommand.js", @@ -203,9 +205,16 @@ "migration:revert": { "path": "#src/commands/MigrationRevertCommand" }, + "db:fresh": { + "path": "#src/commands/DbFreshCommand", + "loadAllCommands": true + }, "db:seed": { "path": "#src/commands/DbSeedCommand" }, + "db:wipe": { + "path": "#src/commands/DbWipeCommand" + }, "make:model": { "path": "#src/commands/MakeModelCommand" }, diff --git a/src/commands/DbFreshCommand.ts b/src/commands/DbFreshCommand.ts new file mode 100644 index 0000000..b2b6ff6 --- /dev/null +++ b/src/commands/DbFreshCommand.ts @@ -0,0 +1,32 @@ +/** + * @athenna/database + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { Artisan, BaseCommand, Option } from '@athenna/artisan' + +export class DbWipeCommand extends BaseCommand { + @Option({ + default: 'default', + signature: '-c, --connection ', + description: 'Set the the database connection.' + }) + public connection: string + + public static signature(): string { + return 'db:fresh' + } + + public static description(): string { + return 'Drop all the tables of your database and run migrations again.' + } + + public async handle(): Promise { + await Artisan.call(`db:wipe --connection ${this.connection}`) + await Artisan.call(`migration:run --connection ${this.connection}`) + } +} diff --git a/src/commands/DbWipeCommand.ts b/src/commands/DbWipeCommand.ts new file mode 100644 index 0000000..cb10d79 --- /dev/null +++ b/src/commands/DbWipeCommand.ts @@ -0,0 +1,63 @@ +/** + * @athenna/database + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { Exec } from '@athenna/common' +import { Database } from '#src/facades/Database' +import { BaseCommand, Option } from '@athenna/artisan' + +export class DbWipeCommand extends BaseCommand { + @Option({ + default: 'default', + signature: '-c, --connection ', + description: 'Set the the database connection.' + }) + public connection: string + + public static signature(): string { + return 'db:wipe' + } + + public static description(): string { + return 'Drop all the tables of your database.' + } + + public async handle(): Promise { + this.logger.simple('({bold,green} [ WIPING DATABASE ])\n') + + const DB = Database.connection(this.connection) + const task = this.logger.task() + + if (this.getConfig('driver') === 'mongo') { + const tables = await DB.getTables() + + await Exec.concurrently(tables, table => DB.dropTable(table)) + } else { + const migrationsTable = this.getConfig( + 'migrations.tableName', + 'migrations' + ) + + await DB.revertMigrations() + await DB.dropTable(migrationsTable) + } + + const dbName = await DB.getCurrentDatabase() + + await task.run().finally(() => DB.close()) + + this.logger.success(`Database ({yellow} "${dbName}") successfully wiped.`) + } + + private getConfig(name: string, defaultValue?: any) { + return Config.get( + `database.connections.${this.connection}.${name}`, + defaultValue + ) + } +} diff --git a/src/commands/MigrationRevertCommand.ts b/src/commands/MigrationRevertCommand.ts index 2824959..141c453 100644 --- a/src/commands/MigrationRevertCommand.ts +++ b/src/commands/MigrationRevertCommand.ts @@ -29,6 +29,14 @@ export class MigrationRevertCommand extends BaseCommand { public async handle(): Promise { 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) const dbName = await DB.getCurrentDatabase() diff --git a/src/commands/MigrationRunCommand.ts b/src/commands/MigrationRunCommand.ts index 34b97d8..dec3ae3 100644 --- a/src/commands/MigrationRunCommand.ts +++ b/src/commands/MigrationRunCommand.ts @@ -29,6 +29,14 @@ export class MigrationRunCommand extends BaseCommand { public async handle(): Promise { 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) const dbName = await DB.getCurrentDatabase() diff --git a/src/models/builders/ModelQueryBuilder.ts b/src/models/builders/ModelQueryBuilder.ts index aa2b15a..df84fe1 100644 --- a/src/models/builders/ModelQueryBuilder.ts +++ b/src/models/builders/ModelQueryBuilder.ts @@ -51,7 +51,6 @@ export class ModelQueryBuilder< this.primaryKeyProperty = this.schema.getMainPrimaryKeyProperty() as any const deletedAtColumn = this.schema.getDeletedAtColumn() - const properties = this.schema.getAllColumnProperties() if (deletedAtColumn) { this.isSoftDelete = true @@ -59,7 +58,7 @@ export class ModelQueryBuilder< this.DELETED_AT_PROP = deletedAtColumn.property } - this.selectColumns = properties + this.selectColumns = this.schema.getAllColumnNames() this.setPrimaryKey(this.primaryKeyName) } diff --git a/src/models/schemas/ModelSchema.ts b/src/models/schemas/ModelSchema.ts index 3f8ab0e..53c5214 100644 --- a/src/models/schemas/ModelSchema.ts +++ b/src/models/schemas/ModelSchema.ts @@ -226,6 +226,13 @@ export class ModelSchema { return this.columns.map(column => column.property) } + /** + * Get all column names as an array of string. + */ + public getAllColumnNames(): string[] { + return this.columns.map(column => column.name) + } + /** * Get all columns where unique option is true. */ diff --git a/tests/fixtures/config/database.ts b/tests/fixtures/config/database.ts index f00a945..a119800 100644 --- a/tests/fixtures/config/database.ts +++ b/tests/fixtures/config/database.ts @@ -12,8 +12,10 @@ export default { connections: { fake: { - driver: 'fake', - validations: true + driver: 'fake' + }, + fakeMongo: { + driver: 'mongo' }, mysql: { driver: 'mysql' diff --git a/tests/unit/commands/DbFreshCommandTest.ts b/tests/unit/commands/DbFreshCommandTest.ts new file mode 100644 index 0000000..f007922 --- /dev/null +++ b/tests/unit/commands/DbFreshCommandTest.ts @@ -0,0 +1,25 @@ +/** + * @athenna/database + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { Path } from '@athenna/common' +import { Test, type Context } from '@athenna/test' +import { BaseCommandTest } from '#tests/helpers/BaseCommandTest' + +export default class DbFreshCommandTest extends BaseCommandTest { + @Test() + public async shouldBeAbleToRunDbFreshCommand({ command }: Context) { + const output = await command.run('db:fresh --connection=fake', { + path: Path.fixtures('consoles/db-console.ts') + }) + + output.assertSucceeded() + output.assertLogged('[ WIPING DATABASE ]') + output.assertLogged('[ RUNNING MIGRATIONS ]') + } +} diff --git a/tests/unit/commands/DbWipeCommandTest.ts b/tests/unit/commands/DbWipeCommandTest.ts new file mode 100644 index 0000000..22573fc --- /dev/null +++ b/tests/unit/commands/DbWipeCommandTest.ts @@ -0,0 +1,25 @@ +/** + * @athenna/database + * + * (c) João Lenon + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +import { Path } from '@athenna/common' +import { Test, type Context } from '@athenna/test' +import { BaseCommandTest } from '#tests/helpers/BaseCommandTest' + +export default class DbWipeCommandTest extends BaseCommandTest { + @Test() + public async shouldBeAbleToWipeTheEntireDatabase({ command }: Context) { + const output = await command.run('db:wipe --connection=fake', { + path: Path.fixtures('consoles/db-console.ts') + }) + + output.assertSucceeded() + output.assertLogged('[ WIPING DATABASE ]') + output.assertLogged('Database "fake" successfully wiped.') + } +} diff --git a/tests/unit/commands/MigrationRevertCommandTest.ts b/tests/unit/commands/MigrationRevertCommandTest.ts index 3b0c5fe..f3dc1db 100644 --- a/tests/unit/commands/MigrationRevertCommandTest.ts +++ b/tests/unit/commands/MigrationRevertCommandTest.ts @@ -33,4 +33,15 @@ export default class MigrationRevertCommandTest extends BaseCommandTest { output.assertLogged('[ REVERTING MIGRATIONS ]') output.assertLogged('[ success ] Successfully reverted migrations on "fake" database.') } + + @Test() + public async shouldSkipRevertingMigrationsIfDriverIsMongo({ command }: Context) { + const output = await command.run('migration:revert --connection=fakeMongo', { + path: Path.fixtures('consoles/db-console.ts') + }) + + output.assertSucceeded() + output.assertLogged('[ REVERTING MIGRATIONS ]') + output.assertLogged('Connection "fakeMongo" is using "mongo" driver and migrations revert will be skipped.') + } } diff --git a/tests/unit/commands/MigrationRunCommandTest.ts b/tests/unit/commands/MigrationRunCommandTest.ts index 91828f0..b75bbb4 100644 --- a/tests/unit/commands/MigrationRunCommandTest.ts +++ b/tests/unit/commands/MigrationRunCommandTest.ts @@ -33,4 +33,15 @@ export default class MigrationRunCommandTest extends BaseCommandTest { output.assertLogged('[ RUNNING MIGRATIONS ]') output.assertLogged('[ success ] Successfully ran migrations on "fake" database.') } + + @Test() + public async shouldSkipRunningMigrationsIfDriverIsMongo({ command }: Context) { + const output = await command.run('migration:run --connection=fakeMongo', { + path: Path.fixtures('consoles/db-console.ts') + }) + + output.assertSucceeded() + output.assertLogged('[ RUNNING MIGRATIONS ]') + output.assertLogged('Connection "fakeMongo" is using "mongo" driver and migrations run will be skipped.') + } }