-
Notifications
You must be signed in to change notification settings - Fork 393
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
Fix missing @QueryParams decorator options #270
Changes from 3 commits
e8cbf59
3e71052
1c97969
6353ca1
4eac44c
1ca0c3c
5aa5087
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -103,32 +103,30 @@ export class ActionParameterHandler { | |
/** | ||
* Normalizes parameter value. | ||
*/ | ||
protected normalizeParamValue(value: any, param: ParamMetadata): Promise<any>|any { | ||
protected async normalizeParamValue(value: any, param: ParamMetadata): Promise<any> { | ||
if (value === null || value === undefined) | ||
return value; | ||
|
||
// map @QueryParams object properties from string to basic types (normalize) | ||
if (param.type === "queries" && typeof value === "object") { | ||
Object.keys(value).map(key => { | ||
const type = Reflect.getMetadata("design:type", param.targetType.prototype, key); | ||
const typeString = typeof type(); | ||
value[key] = this.normalizeValue(value[key], typeString); | ||
}); | ||
} | ||
|
||
switch (param.targetName) { | ||
case "number": | ||
if (value === "") return undefined; | ||
return +value; | ||
|
||
case "number": | ||
case "string": | ||
return value; | ||
|
||
case "boolean": | ||
if (value === "true" || value === "1") { | ||
return true; | ||
|
||
} else if (value === "false" || value === "0") { | ||
return false; | ||
} | ||
|
||
return !!value; | ||
return this.normalizeValue(value, param.targetName); | ||
|
||
case "date": | ||
const parsedDate = new Date(value); | ||
if (isNaN(parsedDate.getTime())) { | ||
return Promise.reject(new BadRequestError(`${param.name} is invalid! It can't be parsed to date.`)); | ||
throw new BadRequestError(`${param.name} is invalid! It can't be parsed to date.`); | ||
} | ||
return parsedDate; | ||
|
||
|
@@ -138,8 +136,41 @@ export class ActionParameterHandler { | |
value = this.transformValue(value, param); | ||
value = this.validateValue(value, param); // note this one can return promise | ||
} | ||
return value; | ||
} | ||
} | ||
|
||
/** | ||
* Normalizes string value to number or boolean. | ||
*/ | ||
protected normalizeValue(value: any, type: string) { | ||
switch (type) { | ||
case "number": | ||
if (value === "") | ||
return undefined; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think if a parameter is passed in the query with no value it should be casted to I will add a normal comment to detail this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've just extracted pleerock's code to separate method, I haven't changed nothing in normalizing logic. I agree that we should convert |
||
const valueNumber = Number(value); | ||
// tslint:disable-next-line:triple-equals | ||
if (valueNumber == value) | ||
return valueNumber; | ||
else | ||
throw new BadRequestError(`${value} can't be parsed to number.`); | ||
|
||
case "string": | ||
return value; | ||
|
||
case "boolean": | ||
if (value === "true" || value === "1") { | ||
return true; | ||
|
||
} else if (value === "false" || value === "0") { | ||
return false; | ||
} | ||
|
||
return Boolean(value); | ||
|
||
default: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should also cover the |
||
return value; | ||
} | ||
return value; | ||
} | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,22 @@ | ||
import {ParamOptions} from "../decorator-options/ParamOptions"; | ||
import {getMetadataArgsStorage} from "../index"; | ||
|
||
/** | ||
* Injects all request's query parameters to the controller action parameter. | ||
* Must be applied on a controller action parameter. | ||
*/ | ||
export function QueryParams(): Function { | ||
export function QueryParams(options?: ParamOptions): Function { | ||
return function (object: Object, methodName: string, index: number) { | ||
getMetadataArgsStorage().params.push({ | ||
type: "queries", | ||
object: object, | ||
method: methodName, | ||
index: index, | ||
parse: false, | ||
required: false | ||
parse: options ? options.parse : false, | ||
required: options ? options.required : undefined, | ||
classTransform: options ? options.transform : undefined, | ||
explicitType: options ? options.type : undefined, | ||
validate: options ? options.validate : undefined, | ||
}); | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH, I don't like this part, I did this as a quick shortcut.
It may introduce some weird behavior when the reflected type is not constructor-like (is it possible in TypeScript?) especially when it's
undefined
, so I think I should check if thetype
is undefined for case like no property type provided in class definition.