Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(errors): use new way to define exceptions #966

Merged
merged 2 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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