Search code examples
javascriptnestjstypeorm

Null value in column of relation violates not-null constraint - NestJS


So. I've setup pretty much everything for the creation of my Item. When i try to run it in Postman i get the error named in the title. The concerning column is cancellation from the table "Item". In postman, I clearly define it as true (which is not null). And also interesting is the fact that it doesn't complain about the delivery column which is the exact same type as cancellation

The error message: error message in question

Postman screenshot: enter image description here

Item entity

import { Category } from './category.entity';
import { Rent } from './rent.entity';
import { User } from './user.entity';
import {
  BaseEntity,
  Column,
  Entity,
  JoinTable,
  ManyToMany,
  ManyToOne,
  OneToOne,
  PrimaryGeneratedColumn,
} from 'typeorm';

@Entity('item')
export class Item {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  description: string;

  @Column()
  price: number;

  @Column()
  delivery: boolean;

  @Column()
  cancellation: boolean;

  @Column({ nullable: true })
  rating: number;

  @Column()
  imageUrl: string;

  @ManyToOne(() => User, (user) => user.items, {
    onDelete: 'CASCADE',
  })
  user: User;

  @OneToOne(() => Rent, (rent) => rent.item)
  rent: Rent;

  @ManyToMany(() => Category, (category) => category.items)
  @JoinTable()
  categories: Category[];
}

Create item DTO

import {
  IsBoolean,
  IsNotEmpty,
  IsNumber,
  IsOptional,
  IsString,
} from 'class-validator';

export class CreateItemDto {
  @IsString()
  @IsNotEmpty()
  name: string;

  @IsString()
  @IsNotEmpty()
  description: string;

  @IsNumber()
  @IsNotEmpty()
  price: number;

  @IsBoolean()
  @IsNotEmpty()
  delivery: boolean;

  @IsBoolean()
  @IsNotEmpty()
  cancellation: boolean;

  @IsOptional()
  rating: number;

  @IsNotEmpty()
  userId: number;

  @IsOptional()
  imageUrl: string;
}

User entity

import { Item } from './item.entity';
import { Rent } from './rent.entity';
import { Review } from './review.entity';
import {
  BaseEntity,
  Column,
  Entity,
  OneToMany,
  PrimaryGeneratedColumn,
} from 'typeorm';

@Entity('user')
export class User extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column('varchar', { length: 50 })
  name: string;

  @Column('varchar', { length: 50 })
  surname: string;

  @Column('varchar', { length: 50 })
  street: string;

  @Column('varchar', { length: 50 })
  city: string;

  @Column('varchar', { length: 5 })
  zip: string;

  @Column({ type: 'int', nullable: true })
  rating: number;

  @Column('varchar', { length: 10 })
  phone: string;

  @Column('date')
  date: Date;

  @Column({ type: 'varchar', length: 50, nullable: false, unique: true })
  email: string;

  @Column({ type: 'varchar', length: 75, nullable: false })
  password: string;

  @OneToMany(() => Review, (review) => review.user)
  reviews: Review[];

  @OneToMany(() => Rent, (rent) => rent.user)
  rents: Rent[];

  @OneToMany(() => Item, (item) => item.user)
  items: Item[];
}

Items service

import { CreateItemDto } from './dto/createItem.dto';
import { ItemsRepository } from './items.repository';
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Item } from 'src/entities/item.entity';
import { User } from 'src/entities/user.entity';

@Injectable()
export class ItemsService {
  constructor(
    @InjectRepository(ItemsRepository)
    private itemsRepository: ItemsRepository,
  ) {}

  async getItemById(id: number) {
    return await this.itemsRepository.findOne(id);
  }

  async createItem(createItemDto: CreateItemDto, user: User): Promise<Item> {
    const newItem = await this.itemsRepository.save({
      name: createItemDto.name,
      description: createItemDto.description,
      price: createItemDto.price,
      delivery: createItemDto.delivery,
      rating: createItemDto.rating,
      imageUrl: createItemDto.imageUrl,
    });

    user.items = [...user.items, newItem];
    await user.save();

    return newItem;
  }
}

Items controller

import { AuthService } from './../auth/auth.service';
import { CreateItemDto } from './dto/createItem.dto';
import { ItemsService } from './items.service';
import { Body, Controller, Post } from '@nestjs/common';
import { Item } from 'src/entities/item.entity';

@Controller('items')
export class ItemsController {
  constructor(
    private itemsService: ItemsService,
    private authService: AuthService,
  ) {}

  @Post('/createitem')
  async createItem(@Body() createItemDto: CreateItemDto): Promise<Item> {
    const user = await this.authService.getUserById(createItemDto.userId);
    return this.itemsService.createItem(createItemDto, user);
  }
}

Auth service

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { SignUpDto } from './dto/signup.dto';
import { SignInDto } from './dto/signin.dto';
import { UsersRepository } from './users.repository';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';
import { JwtPayload } from './jwt-payload.interface';
import { User } from 'src/entities/user.entity';

@Injectable()
export class AuthService {
  constructor(
    @InjectRepository(UsersRepository)
    private usersRepository: UsersRepository,
    private jwtService: JwtService,
  ) {}

  async signUp(signUpDto: SignUpDto): Promise<void> {
    return this.usersRepository.createUser(signUpDto);
  }

  async signIn(signInDto: SignInDto): Promise<{ accessToken: string }> {
    const { email, password } = signInDto;
    const user = await this.usersRepository.findOne({ email });
    if (user && (await bcrypt.compare(password, user.password))) {
      const payload: JwtPayload = { email };
      const accessToken: string = await this.jwtService.sign(payload);
      return { accessToken };
    } else {
      throw new UnauthorizedException('Check your login credentials');
    }
  }
  async getUserById(id: number): Promise<User> {
    return await this.usersRepository.findOne(id, { relations: ['items'] });
  }
}

Items module

import { AuthModule } from './../auth/auth.module';
import { AuthService } from './../auth/auth.service';
import { ItemsRepository } from './items.repository';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Module } from '@nestjs/common';
import { ItemsController } from './items.controller';
import { ItemsService } from './items.service';

@Module({
  imports: [TypeOrmModule.forFeature([ItemsRepository]), AuthModule],
  controllers: [ItemsController],
  providers: [ItemsService],
})
export class ItemsModule {}


Solution

  • You forgot to add the cancellation property:

        const newItem = await this.itemsRepository.save({
      name: createItemDto.name,
      description: createItemDto.description,
      price: createItemDto.price,
      delivery: createItemDto.delivery,
      rating: createItemDto.rating,
      imageUrl: createItemDto.imageUrl,
      cancellation: createItemDto.cancellation, // this one
    });