Skip to content

Commit

Permalink
Added parseToInstance property
Browse files Browse the repository at this point in the history
  • Loading branch information
incetarik committed Sep 28, 2023
1 parent f6d2043 commit 47125dc
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 8 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ This file contains the changes made to the package.

The sections are in descending order of the change date.

## [3.3.0] - 2023-07-05
## [3.3.0] - 2023-09-28
### Added
- Support for `NativeEnum`s.
- `parseToInstance` option to let users/consumers choose if the successful
`zod` validation should parse to the instance of dynamically generated class.

## [3.2.0] - 2023-05-16
### Added
Expand Down
13 changes: 12 additions & 1 deletion src/decorators/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,18 @@ export function MethodWithZodModel<T extends AnyZodObject>(
let newDescriptor = descriptor || {}

const originalFunction = descriptor?.value ?? target[ methodName ]
const decoratedFunction = decorateWithZodInput(originalFunction, input, model)

let decorationProps: typeof nameOrOptions
if (typeof nameOrOptions === 'string') {
decorationProps = {
zod: { parseToInstance: true },
}
}
else {
decorationProps = nameOrOptions
}

const decoratedFunction = decorateWithZodInput(originalFunction, input, model, decorationProps)

newDescriptor.value = decoratedFunction

Expand Down
20 changes: 15 additions & 5 deletions src/decorators/decorate-with-zod-input.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { BaseOptions } from './zod-options-wrapper.interface'
import type { DynamicZodModelClass } from './types'

import { plainToInstance } from 'class-transformer'
import { AnyZodObject, ZodError } from 'zod'

import { BadRequestException } from '@nestjs/common'

import { DynamicZodModelClass } from './types'

type Fn = (...args: any) => any

/**
Expand All @@ -28,14 +29,23 @@ export function decorateWithZodInput<
>(
originalFunction: F,
input: T,
model: DynamicZodModelClass<T>
model: DynamicZodModelClass<T>,
options?: BaseOptions<T>
) {
return function _modelWithZod(this: any, ...args: Parameters<F>) {
const result = originalFunction.apply(this, args)
let parseToInstance = true

if (typeof options?.zod === 'object') {
if (typeof options.zod.parseToInstance === 'boolean') {
parseToInstance = options.zod.parseToInstance
}
}

if (result instanceof Promise) {
return result
.then(output => input.parseAsync(output))
.then((output) => plainToInstance(model, output))
.then(output => parseToInstance ? plainToInstance(model, output) : output)
.catch((error: Error) => {
if (error instanceof ZodError) {
throw new BadRequestException(error.issues)
Expand All @@ -48,7 +58,7 @@ export function decorateWithZodInput<
else {
const parseResult = input.safeParse(result)
if (parseResult.success) {
return plainToInstance(model, parseResult.data)
return parseToInstance ? plainToInstance(model, parseResult.data) : parseResult.data
}
else {
throw new BadRequestException(parseResult.error.issues)
Expand Down
12 changes: 11 additions & 1 deletion src/model-from-zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Type } from '@nestjs/common'
import type { EnumProvider } from './types/enum-provider'
import type { TypeProvider } from './types/type-provider'

import { AnyZodObject, ParseParams, TypeOf, ZodError, ZodTypeAny } from 'zod'
import type { AnyZodObject, ParseParams, TypeOf, ZodError, ZodTypeAny } from 'zod'

import { ObjectType, ObjectTypeOptions } from '@nestjs/graphql'

Expand Down Expand Up @@ -56,6 +56,16 @@ export interface IModelFromZodOptions<T extends ZodTypeAny>
*/
keepZodObject?: boolean

/**
* Indicates whether or not the successfully parsed objects should
* be converted to their dynamically built class instances.
*
* @type {boolean}
* @memberof IModelFromZodOptions
* @default true
*/
parseToInstance?: boolean

/**
* A function that can be used for providing a default value for a property
* that had an error during parsing.
Expand Down

0 comments on commit 47125dc

Please sign in to comment.