Skip to content

Commit

Permalink
feat(errors): use new way to define exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
RomainLanz committed Oct 5, 2023
1 parent a66f901 commit aec69f7
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 145 deletions.
1 change: 1 addition & 0 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
* file that was distributed with this source code.
*/

export * as errors from './src/errors.js'
export { configure } from './configure.js'
export { stubsRoot } from './stubs/main.js'
export { defineConfig } from './src/define_config.js'
12 changes: 3 additions & 9 deletions src/connection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
import { Pool } from 'tarn'
import knex, { Knex } from 'knex'
import { EventEmitter } from 'node:events'
import { Exception } from '@poppinss/utils'
import { patchKnex } from 'knex-dynamic-connection'
import type { Logger } from '@adonisjs/core/logger'
// @ts-expect-error
import { resolveClientNameWithAliases } from 'knex/lib/util/helpers.js'
import { ConnectionConfig, ConnectionContract, ReportNode } from '../types/database.js'

import { Logger as ConnectionLogger } from './logger.js'
import * as errors from '../errors.js'

/**
* Connection class manages a given database connection. Internally it uses
Expand Down Expand Up @@ -81,17 +81,11 @@ export class Connection extends EventEmitter implements ConnectionContract {
private validateConfig(): void {
if (this.config.replicas) {
if (!this.config.replicas.read || !this.config.replicas.write) {
throw new Exception('Make sure to define read/write replicas or use connection property', {
code: 'E_INCOMPLETE_REPLICAS_CONFIG',
status: 500,
})
throw new errors.E_INCOMPLETE_REPLICAS_CONFIG()
}

if (!this.config.replicas.read.connection || !this.config.replicas.read.connection) {
throw new Exception('Make sure to define connection property inside read/write replicas', {
status: 500,
code: 'E_INVALID_REPLICAS_CONFIG',
})
throw new errors.E_INVALID_REPLICAS_CONFIG()
}
}
}
Expand Down
7 changes: 2 additions & 5 deletions src/connection/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
* file that was distributed with this source code.
*/

import { Exception } from '@poppinss/utils'
import type { Emitter } from '@adonisjs/core/events'
import type { Logger } from '@adonisjs/core/logger'

Expand All @@ -20,6 +19,7 @@ import {
} from '../types/database.js'

import { Connection } from './index.js'
import * as errors from '../errors.js'

/**
* Connection manager job is to manage multiple named connections. You can add any number
Expand Down Expand Up @@ -126,10 +126,7 @@ export class ConnectionManager implements ConnectionManagerContract {
connect(connectionName: string): void {
const connection = this.connections.get(connectionName)
if (!connection) {
throw new Exception(`Cannot connect to unregistered connection ${connectionName}`, {
code: 'E_UNMANAGED_DB_CONNECTION',
status: 500,
})
throw new errors.E_UNMANAGED_DB_CONNECTION([connectionName])
}

/**
Expand Down
9 changes: 5 additions & 4 deletions src/database/query_builder/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { DBQueryCallback, DatabaseQueryBuilderContract } from '../../types/query
import { Chainable } from './chainable.js'
import { QueryRunner } from '../../query_runner/index.js'
import { SimplePaginator } from '../paginator/simple_paginator.js'
import * as errors from '../../errors.js'

/**
* Wrapping the user function for a query callback and give them
Expand All @@ -29,7 +30,7 @@ const queryCallback: DBQueryCallback = (userFn, keysResolver) => {
return (builder: Knex.QueryBuilder) => {
/**
* Sub queries don't need the client, since client is used to execute the query
* and subqueries are not executed seperately. That's why we just pass
* and sub-queries are not executed separately. That's why we just pass
* an empty object.
*
* Other option is to have this method for each instance of the class, but this
Expand Down Expand Up @@ -198,7 +199,7 @@ export class DatabaseQueryBuilder extends Chainable implements DatabaseQueryBuil
async firstOrFail(): Promise<any> {
const row = await this.first()
if (!row) {
throw new Exception('Row not found', { status: 404, code: 'E_ROW_NOT_FOUND' })
throw new errors.E_ROW_NOT_FOUND()
}

return row
Expand Down Expand Up @@ -330,8 +331,8 @@ export class DatabaseQueryBuilder extends Chainable implements DatabaseQueryBuil
/**
* Implementation of `finally` for the promise API
*/
finally(fullfilled: any) {
return this.exec().finally(fullfilled)
finally(fulfilled: any) {
return this.exec().finally(fulfilled)
}

/**
Expand Down
74 changes: 74 additions & 0 deletions src/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* @adonisjs/lucid
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { createError } from '@poppinss/utils'

export const E_INVALID_DATE_COLUMN_VALUE = createError<[string, string | null]>(
'Invalid value for "%s". %s',
'E_INVALID_DATE_COLUMN_VALUE',
500
)

export const E_UNMANAGED_DB_CONNECTION = createError<[string]>(
'Cannot connect to unregistered connection %s',
'E_UNMANAGED_DB_CONNECTION',
500
)

export const E_MISSING_MODEL_ATTRIBUTE = createError<[string, string, string]>(
'"%s" expects "%s" to exist on "%s" model, but is missing',
'E_MISSING_MODEL_ATTRIBUTE',
500
)

export const E_INCOMPLETE_REPLICAS_CONFIG = createError(
'Make sure to define read/write replicas or use connection property',
'E_INCOMPLETE_REPLICAS_CONFIG',
500
)

export const E_INVALID_REPLICAS_CONFIG = createError(
'Make sure to define connection property inside read/write replicas',
'E_INVALID_REPLICAS_CONFIG',
500
)

export const E_MODEL_DELETED = createError(
'Cannot mutate delete model instance',
'E_MODEL_DELETED',
500
)

export const E_ROW_NOT_FOUND = createError('Row not found', 'E_ROW_NOT_FOUND', 404)

export const E_UNABLE_ACQUIRE_LOCK = createError(
'Unable to acquire lock. Concurrent migrations are not allowed',
'E_UNABLE_ACQUIRE_LOCK',
500
)

export const E_UNABLE_RELEASE_LOCK = createError(
'Migration completed, but unable to release database lock',
'E_UNABLE_RELEASE_LOCK',
500
)

export const E_MISSING_SCHEMA_FILES = createError(
'Cannot perform rollback. Schema file "%s" is missing',
'E_MISSING_SCHEMA_FILES',
500
)

export const E_UNDEFINED_RELATIONSHIP = createError(
'"%s" is not defined as a relationship on "%s" model',
'E_UNDEFINED_RELATIONSHIP',
500
)

export const E_RUNTIME_EXCEPTION = createError('%s', 'E_RUNTIME_EXCEPTION', 500)
27 changes: 12 additions & 15 deletions src/migration/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import slash from 'slash'
import { EventEmitter } from 'node:events'
import { Exception } from '@poppinss/utils'
import { MigratorOptions, MigratedFileNode, MigrationListNode } from '../types/migrator.js'

import {
Expand All @@ -24,6 +23,7 @@ import { MigrationSource } from './source.js'
import { Database } from '../database/main.js'
import { Application } from '@adonisjs/core/app'
import { BaseSchema } from '../schema/main.js'
import * as errors from '../errors.js'

/**
* Migrator exposes the API to execute migrations using the schema files
Expand All @@ -45,7 +45,7 @@ export class MigrationRunner extends EventEmitter {
private schemaVersionsTableName: string

/**
* Whether or not the migrator has been booted
* Whether the migrator has been booted
*/
private booted: boolean = false

Expand Down Expand Up @@ -254,7 +254,7 @@ export class MigrationRunner extends EventEmitter {

/**
* Acquires a lock to disallow concurrent transactions. Only works with
* `Mysql`, `PostgreSQL` and `MariaDb` for now.
* `Mysql`, `PostgresSQL` and `MariaDb` for now.
*
* Make sure we are acquiring lock outside the transactions, since we want
* to block other processes from acquiring the same lock.
Expand All @@ -269,14 +269,14 @@ export class MigrationRunner extends EventEmitter {

const acquired = await this.client.dialect.getAdvisoryLock(1)
if (!acquired) {
throw new Exception('Unable to acquire lock. Concurrent migrations are not allowed')
throw new errors.E_UNABLE_ACQUIRE_LOCK()
}
this.emit('acquire:lock')
}

/**
* Release a lock once complete the migration process. Only works with
* `Mysql`, `PostgreSQL` and `MariaDb` for now.
* `Mysql`, `PostgresSQL` and `MariaDb` for now.
*/
private async releaseLock() {
if (!this.client.dialect.supportsAdvisoryLocks || this.disableLocks) {
Expand All @@ -285,15 +285,15 @@ export class MigrationRunner extends EventEmitter {

const released = await this.client.dialect.releaseAdvisoryLock(1)
if (!released) {
throw new Exception('Migration completed, but unable to release database lock')
throw new errors.E_UNABLE_RELEASE_LOCK()
}
this.emit('release:lock')
}

/**
* Makes the migrations table (if missing). Also created in dry run, since
* we always reads from the schema table to find which migrations files to
* execute and that cannot done without missing table.
* execute and that cannot be done without missing table.
*/
private async makeMigrationsTable() {
const hasTable = await this.client.schema.hasTable(this.schemaTableName)
Expand Down Expand Up @@ -332,7 +332,7 @@ export class MigrationRunner extends EventEmitter {
}

/**
* Returns the latest migrations version. If no rows exists
* Returns the latest migrations version. If no rows exist
* it inserts a new row for version 1
*/
private async getLatestVersion() {
Expand All @@ -349,7 +349,7 @@ export class MigrationRunner extends EventEmitter {
/**
* Upgrade migrations name from version 1 to version 2
*/
private async upgradeFromOnetoTwo() {
private async upgradeFromOneToTwo() {
const migrations = await this.getMigratedFilesTillBatch(0)
const client = await this.getClient(false)

Expand All @@ -368,7 +368,7 @@ export class MigrationRunner extends EventEmitter {
await client.from(this.schemaVersionsTableName).where('version', 1).update({ version: 2 })
await this.commit(client)
} catch (error) {
this.rollback(client)
await this.rollback(client)
throw error
}
}
Expand All @@ -379,7 +379,7 @@ export class MigrationRunner extends EventEmitter {
private async upgradeVersion(latestVersion: number): Promise<void> {
if (latestVersion === 1) {
this.emit('upgrade:version', { from: 1, to: 2 })
await this.upgradeFromOnetoTwo()
await this.upgradeFromOneToTwo()
}
}

Expand Down Expand Up @@ -488,10 +488,7 @@ export class MigrationRunner extends EventEmitter {
existing.forEach((file) => {
const migration = collected.find(({ name }) => name === file.name)
if (!migration) {
throw new Exception(`Cannot perform rollback. Schema file {${file.name}} is missing`, {
status: 500,
code: 'E_MISSING_SCHEMA_FILES',
})
throw new errors.E_MISSING_SCHEMA_FILES([file.name])
}

this.migratedFiles[migration.name] = {
Expand Down
2 changes: 1 addition & 1 deletion src/orm/adapter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class Adapter implements AdapterContract {
}

/**
* Returns query client for a model instance by inspecting it's options
* Returns query client for a model instance by inspecting its options
*/
modelClient(instance: LucidRow): any {
const modelConstructor = instance.constructor as unknown as LucidModel
Expand Down
Loading

0 comments on commit aec69f7

Please sign in to comment.