Skip to content

Commit

Permalink
feat(rules): add custom rules
Browse files Browse the repository at this point in the history
  • Loading branch information
jlenon7 committed May 11, 2024
1 parent 51b6d24 commit d4fb2ec
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 5 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@athenna/validator",
"version": "4.1.0",
"version": "4.2.0",
"description": "Template for new projects.",
"license": "MIT",
"author": "João Lenon <lenon@athenna.io>",
Expand Down
93 changes: 91 additions & 2 deletions src/providers/ValidatorProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,56 @@

import { sep } from 'node:path'
import { Config } from '@athenna/config'
import { SimpleErrorReporter } from '#src'
import { Exec, Module, Path } from '@athenna/common'
import { Validate, SimpleErrorReporter } from '#src'
import { Is, Exec, Module, Path } from '@athenna/common'
import { Annotation, ServiceProvider } from '@athenna/ioc'
import { ValidatorImpl } from '#src/validator/ValidatorImpl'
import { ValidationException } from '#src/exceptions/ValidationException'

type UniqueOptions = {
/**
* The table where the database will lookup for the data.
*/
table: string

/**
* The column name in database. If not defined, the name
* of the field in the schema will be used.
*
* @default 'fieldNameInYourSchema'
*/
column?: string

/**
* Use the max field to stablish a max limit for your validation.
* In some cases in your database you might have a max of 10 tuples
* with the same data. Use this option to validate that the number
* of fields registered in database cannot be bigger than the number
* defined on this option.
*
* @example
* ```ts
* const schema = this.validator.object({
* name: this.validator.string().unique({ table: 'users', max: 10 })
* })
*
* const data = { name: 'lenon' }
*
* // Will throw if there are 10 users with name `lenon`
* // created in database
* await this.validator.validate({ schema: this.schema, data })
* ```
* @default undefined
*/
max?: number
}

declare module '@vinejs/vine' {
interface VineString {
unique(options: UniqueOptions): this
}
}

class ErrorReporter extends SimpleErrorReporter {
createError(): any {
return new ValidationException(this.errors)
Expand All @@ -32,6 +76,51 @@ export class ValidatorProvider extends ServiceProvider {
await this.registerValidators()
}

public async boot() {
if (!ioc.has('Athenna/Core/Database')) {
return
}

const DB = ioc.safeUse('Athenna/Core/Database')

Validate.extend().string('unique', async (value, options, field) => {
/**
* We do not want to deal with non-string
* values. The "string" rule will handle the
* the validation.
*/
if (!Is.String(value)) {
return
}

if (!options.column) {
options.column = field.name as string
}

if (options.max) {
const rows = await DB.table(options.table)
.select(options.column)
.where(options.column, value)
.findMany()

if (rows.length > options.max) {
field.report('The {{ field }} field is not unique', 'unique', field)
}

return
}

const existsRow = await DB.table(options.table)
.select(options.column)
.where(options.column, value)
.exists()

if (existsRow) {
field.report('The {{ field }} field is not unique', 'unique', field)
}
})
}

public async registerValidators() {
const validators = Config.get<string[]>('rc.validators', [])

Expand Down

0 comments on commit d4fb2ec

Please sign in to comment.