Marko Marchisio
Marko Marchisio

Reputation: 497

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 {}

Upvotes: 2

Views: 11089

Answers (3)

christianbueno.1
christianbueno.1

Reputation: 592

If you have added a one-to-many relationship between entities, in your Nestjs project. Or some other relationship. You can delete all the rows of the each tables in question to fix the error.

For example ins a one-to-many relationship.

User 1-->* Task

user.entity.ts

@Entity()
export class User {

  @PrimaryGeneratedColumn()
  id: number;

  @Column({ unique: true})
  username: string;

  @Column()
  password: string;

  @Column({ unique: true})
  email: string;

  @OneToMany(() => Task, (task) => task.user)
  @JoinColumn({ name: 'id', referencedColumnName: 'userId'})
  tasks: Task[];

}

task.entity.ts

@Entity()
export class Task {
  @PrimaryGeneratedColumn()
  id: number;

  // @Column({ unique: true})
  @Column('text')
  description: string;

  @Column({ type: 'enum', enum: TaskStatus, default: TaskStatus.OPEN})
  status: TaskStatus;

  @Column({ name: 'created_at', type: 'timestamp', default: () => 'CURRENT_TIMESTAMP'})
  date: Date;

  @DeleteDateColumn({ name: 'deleted_at', type: 'timestamp', nullable: true })
  deletedAt: Date;

  @Column({ name: 'user_id'})
  userId: number;

  @ManyToOne(() => User, (user) => user.tasks)
  @JoinColumn({ name: 'userId'})
  user: User;
}

Delete all rows of the two tables.

delete from user;
delete from task ;

Upvotes: 0

Immanuel
Immanuel

Reputation: 1

posting usernamne password in postman with x-www-form-data

Upvotes: -4

Ayoub Touba
Ayoub Touba

Reputation: 2987

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
});

Upvotes: 1

Related Questions