nestjsx / crud

NestJs CRUD for RESTful APIs
https://github.com/nestjsx/crud/wiki
MIT License
4.01k stars 526 forks source link

Added class transform options #811

Closed xTCry closed 1 year ago

xTCry commented 1 year ago

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Added the possibility of optional transformation of classes for entities

Does this PR introduce a breaking change?

Other information

xTCry commented 1 year ago

Example usage This allows to get and update only the available fields by user role.

user.controller.ts

@Feature(User.name)
@Crud({
  model: { type: User },
  query: {
    join: {
      balances: { eager: true },
    },
    softDelete: true,
  },
  routes: {
    only: ['getOneBase', 'getManyBase', 'updateOneBase', 'replaceOneBase'],
    getOneBase: {
      decorators: [
        AllowedRoles(UserRole.ADMIN, UserRole.DEFAULT),
      ],
    },
    getManyBase: {
      decorators: [
        AllowedRoles(UserRole.ADMIN, UserRole.DEFAULT),
      ],
    },
    updateOneBase: {
      returnShallow: true,
      decorators: [AllowedRoles(UserRole.ADMIN)],
    },
    replaceOneBase: {
      returnShallow: true,
      decorators: [AllowedRoles(UserRole.ADMIN)],
    },
  },
  validation: {
    transform: true,
    transformOptions: {
      groups: [FOR_ALL],
    },
  },
})
@CrudAuth({
  property: 'user',
  groups: (user: User) => user.role,
})
@Controller('user')
export class UserController implements CrudController<User> {
  constructor(
    public readonly service: UserService,
  ) {}
}

user.entity.ts

import { Exclude, Expose, plainToClass } from 'class-transformer';
import {
  Column,
  CreateDateColumn,
  Entity,
  OneToMany,
  PrimaryGeneratedColumn,
  UpdateDateColumn,
} from 'typeorm';
import { UserRole, FOR_ALL } from '@my-common';
import { DefaultTransform } from '@my-common/decorator';

import { UserBalance } from './user-balance.entity';

@Entity()
@Exclude()
export class User {
  @Expose()
  @PrimaryGeneratedColumn()
  public id: number;

  @Expose({ groups: [FOR_ALL, UserRole.ADMIN] })
  @Column({ type: 'character varying', length: 32, nullable: true })
  public username: string | null;

  @Expose({ groups: [FOR_ALL, UserRole.ADMIN] })
  @Column({ type: 'character varying', nullable: true })
  public fullname: string | null;

  @Expose()
  @Column({ type: 'enum', enum: UserRole, default: UserRole.DEFAULT })
  @DefaultTransform(UserRole.DEFAULT, { toClassOnly: true })
  public role: UserRole;

  @Expose({ groups: [FOR_ALL, UserRole.ADMIN] })
  @Column({ type: 'character varying', nullable: true })
  @DefaultTransform(null, { toClassOnly: true })
  public notes: string;

  @Expose({ groups: [FOR_ALL, UserRole.ADMIN] })
  @OneToMany(() => UserBalance, (balance) => balance.user)
  public balances: UserBalance[];

  @Expose()
  @CreateDateColumn()
  public createdAt: Date;

  @Expose()
  @UpdateDateColumn()
  public updatedAt: Date;

  constructor(input?: Partial<User>) {
    if (input) {
      Object.assign(this, plainToClass(User, input, { groups: [FOR_ALL] }));
    }
  }
}