2021-06-02 01:59:40 +00:00
|
|
|
import {Container, Injectable, InjectParam} from '../di'
|
2021-06-03 03:36:25 +00:00
|
|
|
import {Request} from '../http/lifecycle/Request'
|
2021-06-02 01:59:40 +00:00
|
|
|
import {Valid, ValidationRules} from './rules/types'
|
|
|
|
import {Validator} from './Validator'
|
2021-06-03 03:36:25 +00:00
|
|
|
import {AppClass} from '../lifecycle/AppClass'
|
|
|
|
import {DataContainer} from '../http/lifecycle/Request'
|
2021-06-02 01:59:40 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Base class for defining reusable validators for request routes.
|
|
|
|
* If instantiated with a container, it must be a request-level container,
|
|
|
|
* but the type interface allows any data-container to be used when creating
|
|
|
|
* manually.
|
|
|
|
*
|
|
|
|
* You should mark implementations of this class as singleton to avoid
|
|
|
|
* re-validating the input data every time it is accessed.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* ```ts
|
|
|
|
* // Instantiate with the request:
|
|
|
|
* const data = <MyFormRequest> request.make(MyFormRequest)
|
|
|
|
*
|
|
|
|
* // Instantiate with some container:
|
|
|
|
* const data = new MyFormRequest(someDataContainer)
|
|
|
|
* ```
|
|
|
|
*/
|
|
|
|
@Injectable()
|
|
|
|
export abstract class FormRequest<T> extends AppClass {
|
|
|
|
/** The cached validation result. */
|
|
|
|
protected cachedResult?: Valid<T>
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
@InjectParam(Request)
|
2021-06-03 03:36:25 +00:00
|
|
|
protected readonly data: DataContainer,
|
|
|
|
) {
|
|
|
|
super()
|
|
|
|
}
|
2021-06-02 01:59:40 +00:00
|
|
|
|
2021-06-03 03:36:25 +00:00
|
|
|
protected container(): Container {
|
2021-06-02 01:59:40 +00:00
|
|
|
return (this.data as unknown) as Container
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The validation rules that should be applied to the request to guarantee
|
|
|
|
* that it contains the given data type.
|
|
|
|
* @protected
|
|
|
|
*/
|
|
|
|
protected abstract getRules(): ValidationRules | Promise<ValidationRules>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Validate and get the request input. Throws a validation error on fail.
|
|
|
|
* Internally, caches the result after the first validation. So, singleton
|
|
|
|
* validators will avoid re-processing their rules every time.
|
|
|
|
*/
|
|
|
|
public async get(): Promise<Valid<T>> {
|
|
|
|
if ( !this.cachedResult ) {
|
|
|
|
const validator = <Validator<T>> this.make(Validator, await this.getRules())
|
|
|
|
this.cachedResult = await validator.validate(this.data.input())
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.cachedResult
|
|
|
|
}
|
|
|
|
}
|