TECNOLOBO

No recuerdas tu codigo?
Se te olvido como se hace?

Aqui podras guardar lo que necesiten
Y cuando sea necesesario

Creado por julian gomez
iiiiii

Relaciones ORM



Descripcion

Realizar una relacion entre prod y imagenes produc

Nota1


0. teners inatalado el paquete typeorm . documentacion "https://orkhan.gitbook.io/typeorm/docs/relations"
1. crea las dos entidades
2. creamos un product DTO(para crear un nuevo producto) para ver que estrucutra va a teners los productos
3. se crea en entity producto el "@OneToMany()"
4. ahora realizamos la relacion de imagenes  hacia producto usando a "@ManyToOne"
5. se crea un servicio para crear las imagenes y guardar el producto relacion a imagenes
6. se realiza un findAll para listar productos con sus imagenes




NOTA: tambien se peude poner en el findAll los datos de relacion agregando la siguiente propiedad
@OneToMany(
  () => ProductImage,
  (productImage) => productImage.product,
  { cascade: true, eager: true } //eager en true
)
pero este tipo de configuracio solo se puede hacer si estas usando findAll, findXXX etc no al usar "createQueryBuilder"
para estos casos de usa "leftJoinAndSelect"
						

Modulo


//CREAR PRODUCTO
import { IsArray, IsIn, IsInt, IsNumber, IsOptional, 
         IsPositive, IsString, MinLength 
} from 'class-validator';


export class CreateProductDto {

    @IsString()
    @MinLength(1)
    title: string;

    @IsNumber()
    @IsPositive()
    @IsOptional()
    price?: number;

    @IsString()
    @IsOptional()
    description?: string;

    @IsString()
    @IsOptional()
    slug?: string;

    @IsInt()
    @IsPositive()
    @IsOptional()
    stock?: number; 

    @IsString({ each: true })
    @IsArray()
    sizes: string[]

    @IsIn(['men','women','kid','unisex'])
    gender: string;

    @IsString({ each: true })
    @IsArray()
    @IsOptional()
    tags: string[];


    @IsString({ each: true })
    @IsArray()
    @IsOptional()
    images?: string[];


}

						

Servicio


import { BadRequestException, Injectable, InternalServerErrorException, Logger, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DataSource, Repository } from 'typeorm'; //Aqui se usa el Repositori de typeorm para enlazar las entidades.

import { CreateProductDto } from './dto/create-product.dto';
import { UpdateProductDto } from './dto/update-product.dto';
import { PaginationDto } from 'src/common/dtos/pagination.dto';

import { validate as isUUID } from 'uuid';
import { ProductImage, Product } from './entities';

@Injectable()
export class ProductsService {

  private readonly logger = new Logger('ProductsService');

  constructor(

    @InjectRepository(Product)
    private readonly productRepository: Repository<Product>, //enlazamos entidad de productos

    @InjectRepository(ProductImage)
    private readonly productImageRepository: Repository<ProductImage>, //Aqui se enlaza la entidad de imagenes


  ) {}


	
  async create(createProductDto: CreateProductDto) {
    
    try {
      
      /*NOTA: lo que se hace
      con est ainstruccion 
      images: images.map( image => this.productImageRepository.create({ url: image }) )
      es decir que la propiedad imagen:  se va retornar una instancia de tipo objeto productImageRepository para que cree el producto con la ralacion. 
      */
      
      const { images = [], ...productDetails } = createProductDto; //El product dto 

      const product = this.productRepository.create({
        ...productDetails,
        images: images.map( image => this.productImageRepository.create({ url: image }) ) //Aqui no se espesifca el producto que relaciona las imagenes ya que typeORM lo hace
      });
      
      await this.productRepository.save( product );

      return { ...product, images };
      
    } catch (error) {
      this.handleDBExceptions(error);
    }


  }


  /*Mostar los productos con sus imagenes relacionadas con la siguiente instruccion.
   relations: {
        images: true,
      }
  */
  async findAll( paginationDto: PaginationDto ) {

    const { limit = 10, offset = 0 } = paginationDto;

    const products = await this.productRepository.find({
      take: limit,
      skip: offset,
      relations: {
        images: true,
      }
    })
	
    /*Aqui lo unico que se hace con el codigo " return products.map" como cada producto regresa lo siguiente  
    {
    	prodi1:0
        ,prodi2:0
        prodi3:0
        images:[
        {id:1,'url1'},
        {id:2,'url1'}
        ]
    }
    
    se cambia a 
    {
    	prodi1:0
        ,prodi2:0
        prodi3:0
        images:[
        'url1',
        'url1'
        ]
    }
    
    */
    
    return products.map( ( product ) => ({
      ...product,
      images: product.images.map( img => img.url )
    }))
  }



}

						

Entity


/*****PRODUCTOS****/
import { BeforeInsert, BeforeUpdate, Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { ProductImage } from './';

@Entity({ name: 'products' })
export class Product {

    @PrimaryGeneratedColumn('uuid')
    id: string;

    @Column('text', {
        unique: true,
    })
    title: string;

    @Column('float',{
        default: 0
    })
    price: number;

    @Column({
        type: 'text',
        nullable: true
    })
    description: string;

    @Column('text', {
        unique: true
    })
    slug: string;

    @Column('int', {
        default: 0
    })
    stock: number;

    @Column('text',{
        array: true
    })
    sizes: string[];

    @Column('text')
    gender: string;


    @Column('text', {
        array: true,
        default: []
    })
    tags: string[];

    // images un producto puede tener muchas IMAGENES
    @OneToMany(
        () => ProductImage,
        (productImage) => productImage.product,
        { cascade: true, eager: true }
    )
    images?: ProductImage[];


    @BeforeInsert()
    checkSlugInsert() {

        if ( !this.slug ) {
            this.slug = this.title;
        }

        this.slug = this.slug
            .toLowerCase()
            .replaceAll(' ','_')
            .replaceAll("'",'')

    }

    @BeforeUpdate()
    checkSlugUpdate() {
        this.slug = this.slug
            .toLowerCase()
            .replaceAll(' ','_')
            .replaceAll("'",'')
    }


}


/*****IMAGENES******/
import { Product } from './';
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';


@Entity({ name: 'product_images' })
export class ProductImage {

    @PrimaryGeneratedColumn()
    id: number;

    @Column('text')
    url: string;

    @ManyToOne(
        () => Product,
        ( product ) => product.images,
        {  onDelete: 'CASCADE' }
    )
    product: Product

}