Uploading form-data with NestJS using Sequelize / PostgreSQL

Viewed 491

I'VE FOUND THE SOLUTION!!!

I'm writing the backend in Nest.Js / PostgreSQL using Sequelize.js. I want to upload form-data (field + file); and save: file to static/uploads, field with file URL to the DB. I've managed to write the code for file upload with Multer.js, but I'm struggling with sending data (not a file actually) to the DB. Please, advise how to write the controller and service.

app.module.ts

@Module({
  imports: [
    ServeStaticModule.forRoot({
      rootPath: process.env.PUBLIC_DIR || path.join(__dirname, '../../public'),
      serveRoot: '/static',
    }),
    DatabaseModule,
    ConfigModule.forRoot({ isGlobal: true }),
    UsersModule,
    AuthModule,
    PostsModule,
    MulterModule.register({
      dest: './static/uploads',
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

posts.module.ts

@Module({
  imports: [
    MulterModule.register({
      dest: 'static/uploads',
    }),
    DatabaseModule,
  ],
  providers: [PostsService, ...postsProviders],
  controllers: [PostsController],
  exports: [PostsService],
})
export class PostsModule {}

file.entity.ts

@Table
export class File extends Model<File> {
    @Column({
        type: DataType.STRING,
        allowNull: false,
    })
    name: string;

    @Column({
        type: DataType.STRING,
        allowNull: false,
    })
    url: string;

    @ForeignKey(() => Post)
    @Column({
        type: DataType.INTEGER,
        allowNull: false,
    })
    postId: number;

    @BelongsTo(() => Post)
    post: Post;
}

file.dto.ts

export class FileDto {
    @IsNotEmpty()
    readonly name: string;

    @IsNotEmpty()
    readonly url: string;
}

posts.controller.ts

@Post('images')
    @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: process.env.PUBLIC_DIR || path.join(__dirname, '../../../public'),
        filename: editFileName,
      }),
      fileFilter: imageFileFilter,
    }),
  )
    async uploadedFile(@UploadedFile() file, @Request() req, @Body() body ): Promise<File> {   
    return await this.postService.createFile(req.post.id, file, body.name);                    
  }

posts.service.ts

import { Injectable, Inject } from '@nestjs/common';
import { Post } from './post.entity';
import { PostDto } from './dto/post.dto';
import { User } from '../users/user.entity';
import { POST_REPOSITORY } from '../../core/constants';
import { FILE_REPOSITORY } from '../../core/constants';

@Injectable()
export class PostsService {
    constructor(
        @Inject(POST_REPOSITORY) private readonly postRepository: typeof Post,
        @Inject(FILE_REPOSITORY) private readonly fileRepository: typeof File,
    ) { }

   async create(post: PostDto, userId): Promise<Post> {
        return await this.postRepository.create<Post>({ ...post, userId });
    }

    async createFile(postId: number, file: any, bodyName ): Promise<File> {
        return await this.fileRepository.save({
          name: bodyName,
          url: `${process.env.URL}/static/${file.filename}`,
          postId: postId,
        });
        }
      
    async findAll(): Promise<Post[]> {
        return await this.postRepository.findAll<Post>({
            include: [{ model: User, attributes: { exclude: ['password'] } }],
        });
    }

    async findOne(id): Promise<Post> {
        return await this.postRepository.findOne({
            where: { id },
            include: [{ model: User, attributes: { exclude: ['password'] } }],
        });
    }

    async delete(id, userId) {
        return await this.postRepository.destroy({ where: { id, userId } });
    }

    async update(id, data, userId) {
        const [numberOfAffectedRows, [updatedPost]] = await this.postRepository.update({ ...data }, { where: { id, userId }, returning: true });

        return { numberOfAffectedRows, updatedPost };
    }
}

Also, I got an error in posts.service.ts -

 Property 'save' does not exist on type '{ new (fileBits: BlobPart[], fileName: 
 string, options?: FilePropertyBag): File; prototype: File; }'.ts(2339) 

Appreciate any help )

0 Answers
Related