¿Qué aprenderá?

Al finalizar este tutorial el estudiante estará en capacidad de realizar la implementación de la persistencia de una entidad, utilizando Nest.js y TypeORM.

¿Qué necesita?

Para realizar este tutorial Ud. debe:

  1. Tener el ambiente de desarrollo configurado bien sea en su máquina virtual o en su máquina propia
  2. Contar con el modelo de entidades.

El código fuente usado para este tutorial está disponible en el siguiente repositorio:

https://github.com/MISW4403-Diseno-y-construccion-de-APIs/MISW4403_202214_Persistencia

Siguiendo el diagrama de clases que se muestra a continuación, vamos a construir progresivamente una aplicación que permita, a través de una API REST hacer operaciones sobre los recursos listados.

El siguiente diagrama muestra las diferentes clases que existen dentro de la aplicación y cómo se relacionan entre ellas.

El siguiente diagrama muestra la transformación del modelo conceptual al modelo de entidades del caso de estudio. Las decisiones que se toman son las siguientes:

  1. Por cada clase del modelo conceptual se crea una clase que representa la entidad que va a persistir en la base de datos. Esta clase tiene el mismo nombre que en el modelo conceptual.
  2. Para cada clase entidad, se toman todos los extremos opuestos de las relaciones que tiene con otras clases (clases destino de la relación). Cada extremo se anota de acuerdo con la cardinalidad de la asociación.
  3. Dependiendo del caso, en cada anotación también se debe incluir, entre otros:
  1. El atributo correspondiente en la clase destino.
  2. Si la operación de persistencia se va a propagar a las clases relacionadas con esta (Cascade).

Luego de observar el modelo conceptual y el modelo de entidades de la aplicación es un poco más claro el orden de la aplicación. Siguiendo este orden, tomaremos como referencia la clase "Museum" e implementaremos su persistencia.

Como primeros pasos para la creación de la aplicación, debemos crear una nueva aplicación con Nest.js, la cual denominaremos "modern-art-museum". Para esto siga los pasos que se indican en el tutorial para crear una aplicación Nest.js:

https://misovirtual.virtual.uniandes.edu.co/codelabs/MISW4403_202212_AplicacionNest/index.html#0

Como decisión de diseño, por cada recurso del API se creará un módulo.

Iniciaremos creando el módulo para museos. Para esto ejecutamos el comando nest g mo museum. Esto creará la carpeta src/museum y dentro de esa carpeta el archivo museum.module.ts.

Luego de crear el módulo, crearemos la clase MuseumEntity. Para esto ejecutamos el comando nest g cl museum/museum.entity --no-spec. Esto creará el archivo museum.entity.ts dentro de la carpeta src/museum. Como no queremos crear un archivo de pruebas para esa clase incluimos la opción --no-spec en el comando para crear la clase.

Atributos primitivos

Dentro del contexto de la aplicación, un museo tiene los siguientes atributos primitivos:

Como queremos que la clase MuseumEntity se persista en la base de datos, necesitamos agregarle algunas anotaciones de TypeORM; por tanto necesitamos instalar la dependencia de TypeORM para NestJS. Esto se hace ejecutando el siguiente comando en consola.

npm install --save @nestjs/typeorm typeorm

A continuación tenemos el código de la clase MuseumEntity.

/* eslint-disable prettier/prettier */
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class MuseumEntity {
 @PrimaryGeneratedColumn('uuid')
 id: string;

 @Column()
 name: string;
 
 @Column()
 description: string;
 
 @Column()
 address: string;
 
 @Column()
 city: string;

 @Column()
 image: string;
}

Las anotaciones utilizadas en la clase Museum fueron:

Asociaciones

Luego de considerar los atributos primitivos de la clase, se analizan las asociaciones de la clase MuseumEntity. Encontramos entonces dos asociaciones, con Exhibition y Artwork

De este modo la clase MuseumEntity tendrá, adicionalmente, un atributo por cada asociación en la que el museo participa. Los extremos opuestos de la asociación (del lado de la clase destino) tienen el nombre que se usará para modelar el atributo, en este caso exhibitions y artworks. Además de tener un nombre y un tipo, cada uno de estos atributos debe tener una anotación que le permita a TypeORM crear adecuadamente las tablas.

Asociación Museum-Exhibition

Esta es una relación de uno a muchos (OneToMany), ya que por cada museo hay muchas exhibiciones, pero una exhibición solo se ofrece en un museo.

En TypeScript, la clase MuseumEntity tendrá la siguiente definición del atributo exhibitions:

...
    @OneToMany(() => ExhibitionEntity, exhibition => exhibition.museum)
   exhibitions: ExhibitionEntity[];

...

Este atributo se encuentra anotado con @OneToMany, que es la anotación a través de la cual se hace una relación uno a muchos. En este caso, un museo puede tener asociadas varias exhibiciones, pero una exhibición solo puede estar asociada a un museo. Note que en este caso, el atributo exhibitions es un arreglo.

De manera inversa, en la clase Exhibition, debe existir un atributo denominado museum de tipo MuseumEntity con la anotación @ManyToOne que asocia muchas exhibiciones a un solo museo.

En las asociaciones @OneToMany y @ManyToOne el dueño de la asociación será aquel que tenga la anotación @OneToMany. En este caso, el dueño de la asociación es Museum. Esto significa que será el museo el que se encargará de agregar las exhibiciones y no al contrario. Esto se verá con más claridad en la implementación de la capa de lógica.

Asociación Museum-Artwork

Esta es una relación de uno a muchos (OneToMany), ya que por cada museo hay muchas obras de arte, pero una obra de arte solo pertenece a un museo.

En TypeScript, la clase MuseumEntity tendrá la siguiente definición del atributo artworks:

...
    @OneToMany(() => ArtworkEntity, artwork => artwork.museum)
   artworks: ArtworkEntity[];
...

Implementación Completa

Para resumir, a continuación tenemos la implementación completa de la clase MuseumEntity.

/* eslint-disable prettier/prettier */
/* archivo: src/museum/museum.entity.ts */
import { ArtworkEntity } from '../artwork/artwork.entity';
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { ExhibitionEntity } from '../exhibition/exhibition.entity';

@Entity()
export class MuseumEntity {
   @PrimaryGeneratedColumn('uuid')
   id: string;

   @Column()
   name: string;
   @Column()
   description: string;
   @Column()
   address: string;
   @Column()
   city: string;
   @Column()
   image: string;

   @OneToMany(() => ExhibitionEntity, exhibition => exhibition.museum)
   exhibitions: ExhibitionEntity[];

   @OneToMany(() => ArtworkEntity, artwork => artwork.museum)
   artworks: ArtworkEntity[];

}


/* archivo: src/museum/museum.entity.ts */

En este caso, se obtendrán errores de importación en el archivo, ya que la clase ExhibitionEntity y ArtworkEntity aún no han sido creadas; por tanto implementaremos a continuación estas dos entidades.

Atributos Primitivos

Dentro del contexto de la aplicación, una exhibición tiene los siguientes atributos:

Cree el módulo exhibition y la clase exhibition.entity.ts. Este es el contenido inicial de esa clase

@Entity()
export class ExhibitionEntity {
    @PrimaryGeneratedColumn("uuid")
    id: string;
 
    @Column()
    name: string;
 
    @Column()
    description: string;

}

Las anotaciones utilizadas para esta clase son las mismas que las utilizadas y explicadas al momento de crear la clase MuseumEntity.

Asociaciones

La clase ExhibitionEntity tiene 3 asociaciones: con MuseumEntity , ArtworkEntity y SponsorEntity.

La clase ExhibitionEntity tendrá adicionalmente, un atributo por cada asociación en la que la clase es fuente.

Asociación Exhibition-Museum

Esta es una relación de muchos a uno (ManyToOne), ya que muchas exhibiciones pertenecen a un único museo, pero un museo tiene muchas exhibiciones.

En TypeScript, la clase Exhibition tendrá la siguiente definición del atributo museum:

...
    @ManyToOne(() => MuseumEntity, museum => museum.exhibitions)
   museum: MuseumEntity;
...

Relación Exhibition-Artwork

Esta es una relación uno a muchos (OneToMany), ya que por cada exhibición hay muchas obras de arte, pero una obra de arte solo pertenece a una exhibición.

En TypeScript, la clase Exhibition tendrá la siguiente definición del atributo artworks:

...
    @OneToMany(() => ArtworkEntity, artwork => artwork.exhibition)
   artworks: ArtworkEntity[];
...

Relación Exhibition-Sponsor

Esta es una relación de uno a uno (OneToOne), ya que por cada exhibición solo hay un patrocinador e igualmente un patrocinador patrocina una única exhibición.

En TypeScript, la clase ExhibitionEntity tendrá la siguiente definición del atributo sponsor:

...
   @OneToOne(() => SponsorEntity, sponsor => sponsor.exhibition)
   @JoinColumn()
   sponsor: SponsorEntity;
...

Este atributo está anotado con @OneToOne y @JoinColumn. Lo que indica esta última anotación es que en la relación uno a uno que tiene con Sponsor, Exhibition es el dueño de la asociación. Esto significa que será la exhibición la que "setea" el atributo sponsor y no al contrario.

Implementación Completa

Para resumir, a continuación tenemos la implementación completa de la clase ExhibitionEntity.

/* eslint-disable prettier/prettier */
/* archivo: src/exhibition/exhibition.entity.ts */
import { ArtworkEntity } from "../artwork/artwork.entity";
import { MuseumEntity } from "../museum/museum.entity";
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, OneToOne, PrimaryGeneratedColumn } from "typeorm";
import { SponsorEntity } from "../sponsor/sponsor.entity";

@Entity()
export class ExhibitionEntity {
   @PrimaryGeneratedColumn("uuid")
   id: string;
   @Column()
   name: string;
   @Column()
   description: string;
   @ManyToOne(() => MuseumEntity, museum => museum.exhibitions)
   museum: MuseumEntity;
   @OneToMany(() => ArtworkEntity, artwork => artwork.exhibition)
   artworks: ArtworkEntity[];

   @OneToOne(() => SponsorEntity, sponsor => sponsor.exhibition)
   @JoinColumn()
   sponsor: SponsorEntity;
}
/* archivo: src/exhibition/exhibition.entity.ts */

Los errores de importaciones de otras clases se solucionarán a medida que construyamos las demás clases de la aplicación.

Atributos primitivos

Dentro del contexto de la aplicación una obra de arte tiene los siguientes atributos:

Cree el módulo artwork y dentro del módulo la clase artwork.entity.ts.

Este es el contenido inicial de la clase artwork.entity.ts:

@Entity()
export class ArtworkEntity {
    @PrimaryGeneratedColumn("uuid")
    id: string;
 
    @Column()
    name: string;
 
    @Column()
    year: number;
 
    @Column()
    description: string;
 
    @Column()
    type: string;
 
    @Column()
    mainImage: string;
}

En el archivo podemos observar que se usan las anotaciones que se han explicado para las otras clases.

Asociaciones

La clase ArtworkEntity tiene 4 asociaciones con las clases MuseumEntity, ExhibitionEntity, ImageEntity y ArtistEntity.

La clase Artwork tendrá adicionalmente, un atributo por cada asociación en la que Artwork es fuente.

Asociación Artwork-Museum

Esta es una relación de muchos a uno (ManyToOne), ya que muchas obras de arte pertenecen a un único museo, pero un museo tiene muchas obras de arte.

En TypeScript, la clase ArtworkEntity tendrá la siguiente definición del atributo museum:

...  
   @ManyToOne(() => MuseumEntity, museum => museum.artworks)
   museum: MuseumEntity;
...

Asociación Artwork-Exhibition

Esta es una relación de muchos a uno (ManyToOne), ya que muchas obras de arte pertenecen a una única exhibición, pero en una exhibición se tienen muchas obras de arte.

En TypeScript, la clase Artwork tendrá la siguiente definición del atributo exhibition:

...
    @ManyToOne(() => ExhibitionEntity, exhibition => exhibition.artworks)
   exhibition: ExhibitionEntity;
...

Asociación Artwork-Image

Esta es una relación de uno a muchos (OneToMany), ya que una obra de arte tiene varias imagenes, pero una imagen le pertenece a una obra de arte.

En TypeScript, la clase ArtworkEntity tendrá la siguiente definición del atributo images:

...
    @OneToMany(() => ImageEntity, image => image.artwork)
   images: ImageEntity[];
...

Asociación Artwork-Artist

Esta es una relación de muchos a uno (ManyToOne), ya que una obra de arte fue creada por un único artista, pero un artista ha creado muchas obras de arte.

En TypeScript, la clase ArtworkEntity tendrá la siguiente definición del atributo artist:

...
    @ManyToOne(() => Artist, artist => artist.artworks)
    artist: Artist;
...

Implementación Completa

A continuación tenemos la implementación completa de la clase Artwork.

/* eslint-disable prettier/prettier */
/* archivo: src/artwork/artwork.entity.ts */
import { ExhibitionEntity } from "../exhibition/exhibition.entity";
import { MuseumEntity } from "../museum/museum.entity";
import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn } from "typeorm";
import { ImageEntity } from "../image/image.entity";
import { ArtistEntity } from "../artist/artist.entity";

@Entity()
export class ArtworkEntity {

   @PrimaryGeneratedColumn("uuid")
   id: string;
   @Column()
   name: string;
   @Column()
   year: number;
   @Column()
   description: string;
   @Column()
   type: string;
   @Column()
   mainImage: string;

   @ManyToOne(() => MuseumEntity, museum => museum.artworks)
   museum: MuseumEntity;

   @ManyToOne(() => ExhibitionEntity, exhibition => exhibition.artworks)
   exhibition: ExhibitionEntity;

   @OneToMany(() => ImageEntity, image => image.artwork)
   images: ImageEntity[];

   @ManyToOne(() => ArtistEntity, artist => artist.artworks)
   artist: ArtistEntity;
}
/* archivo: src/artwork/artwork.entity.ts */

Atributos Primitivos

Dentro del contexto de la aplicación, un artista tiene los siguientes atributos:

Cree el módulo artist y dentro de él la clase artist.entity.ts.

Este es el contenido inicial de esa clase:

@Entity()
export class Artist {
    @PrimaryGeneratedColumn("uuid")
    id: string;
 
    @Column()
    name: string;
 
    @Column()
    birthplace: string;
 
    @Column()
    birthdate: Date;
 
    @Column()
    image: string;
}

Asociaciones

La clase ArtistEntity tiene 2 asociaciones con ArtworkEntity y MovementEntity.

La clase ArtistEntity tendrá adicionalmente, un atributo por cada asociación en la que ArtistEntity participa.

Asociación Artist-Artwork

Esta es una relación de uno a muchos (OneToMany), ya que un artista ha creado muchas obras de arte, pero una obra de arte fue creada únicamente por un artista (según nuestra decisión de diseño).

En TypeScript, la clase ArtistEntity tendrá la siguiente definición del atributo artworks:

...
   @OneToMany(() => ArtworkEntity, artwork => artwork.artist)
   artworks: ArtworkEntity[];
...

Asociación Artist-Movement

Esta es una asociación de muchos a muchos (ManyToMany), ya que un artista puede pertenecer a muchos movimientos, y a un movimiento pueden pertenecer muchos artistas.

En TypeScript, la clase ArtistEntity tendrá la siguiente definición del atributo movements:

...
    @ManyToMany(() => MovementEntity, movement => movement.artists)
    movements: MovementEntity[];
...

Una nueva anotación que vemos en este caso es la anotación @ManyToMany que es la anotación que representa una asociación de muchos a muchos.

Implementación Completa

Para resumir, a continuación tenemos la implementación completa de la clase ArtistEntity.

/* eslint-disable prettier/prettier */
/* archivo: src/artist/artist.entity.ts */
import { ArtworkEntity } from "../artwork/artwork.entity";
import { MovementEntity } from "../movement/movement.entity";
import { Column, Entity, ManyToMany, OneToMany, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class ArtistEntity {
   @PrimaryGeneratedColumn("uuid")
   id: string;
   @Column()
   name: string;
   @Column()
   birthplace: string;
   @Column()
   birthdate: Date;
   @Column()
   image: string;

   @OneToMany(() => ArtworkEntity, artwork => artwork.artist)
   artworks: ArtworkEntity[];

   @ManyToMany(() => MovementEntity, movement => movement.artists)
   movements: MovementEntity[];

}
/* archivo: src/artist/artist.entity.ts */

Atributos Primitivos

Dentro del contexto de la aplicación, un patrocinador tiene los siguientes atributos:

Cree el módulo sponsor y dentro de él la clase sponsor.entity.ts. El siguiente es el contenido inicial de esa clase

@Entity()
export class SponsorEntity {
    @PrimaryGeneratedColumn("uuid")
    id: string;
 
    @Column()
    name: string;
 
    @Column()
    description: string;
 
    @Column()
    website: string;
}

Asociaciones

La clase Sponsor tiene 1 asociación con la clase ExhibitionEntity. La clase Sponsor tendrá adicionalmente, un atributo por la asociación en la que Sponsor participa.

Asociación Sponsor-Exhibition

Esta es una relación de uno a uno (OneToOne), ya que un patrocinador solo patrocina una exhibición, y una exhibición solo es patrocinada por un único patrocinador.

En TypeScript, la clase Sponsor tendrá la siguiente definición del atributo exhibition:

...
    @OneToOne(() => ExhibitionEntity, exhibition => exhibition.sponsor)
    exhibition: ExhibitionEntity;
...

Implementación Completa

Para resumir, a continuación tenemos la implementación completa de la clase Sponsor.

/* eslint-disable prettier/prettier */
/* archivo: src/sponsor/sponsor.entity.ts */
import { ExhibitionEntity } from "../exhibition/exhibition.entity";
import { Column, Entity, OneToOne, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class SponsorEntity {
   @PrimaryGeneratedColumn("uuid")
   id: string;
   @Column()
   name: string;
   @Column()
   description: string;
   @Column()
   website: string;

   @OneToOne(() => ExhibitionEntity, exhibition => exhibition.sponsor)
   exhibition: ExhibitionEntity;

}
/* archivo: src/sponsor/sponsor.entity.ts */

Atributos primitivos

Dentro del contexto de la aplicación, una Imagen tiene los siguientes atributos:

Cree el módulo image y dentro de él la clase image.entity.ts. El contenido inicial del archivo es el siguiente:

@Entity()
export class ImageEntity {
    @PrimaryGeneratedColumn("uuid")
    id: string;
 
    @Column()
    source: string;
 
    @Column()
    altText: string;
 
    @Column()
    height: number;
 
    @Column()
    width: number;
}

Asociaciones

La clase ImageEntity tiene 1 asociación con la clase ArtworkEntity. La clase ImageEntity tendrá adicionalmente, un atributo por la asociación en la que ImageEntity es fuente.

Asociación Image-Artwork

Esta es una relación de muchos a uno (ManyToOne), ya que una imagen representa a una única obra de arte, pero una obra de arte es representada por muchas imágenes.

En TypeScript, la clase ImageEntity tendrá la siguiente definición del atributo artwork:

...
    @ManyToOne(() => Artwork, artwork => artwork.images)
    artwork: Artwork;
...

Implementación Completa

Para resumir, a continuación tenemos la implementación completa de la clase ImageEntity.

/* eslint-disable prettier/prettier */
/* archivo: src/image/image.entity.ts */
import { ArtworkEntity } from "../artwork/artwork.entity";
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class ImageEntity {
   @PrimaryGeneratedColumn("uuid")
   id: string;
   @Column()
   source: string;
   @Column()
   altText: string;
   @Column()
   height: number;
   @Column()
   width: number;

   @ManyToOne(() => ArtworkEntity, artwork => artwork.images)
   artwork: ArtworkEntity;
}
/* archivo: src/image/image.entity.ts */

Atributos Primitivos

Dentro del contexto de la aplicación, un movimiento artístico tiene los siguientes atributos:

Cree el módulo movement y dentro de él la clase movement.entity.ts. Este es el contenido inicial de la clase:

@Entity()
export class MovementEntity {
    @PrimaryGeneratedColumn("uuid")
    id: string;
 
    @Column()
    name: string;
 
    @Column()
    description: string;
   
    @Column()
    countryOfOrigin: string;
}

Asociaciones

La clase MovementEntity tiene 1 asociación con la clase ArtistEntity. La clase Movement tendrá adicionalmente, un atributo por la asociación en la que Movement es fuente.

Asociación Movement-Artist

Esta es una relación de muchos a muchos (ManyToMany), ya que un movimiento está representado por muchos artistas, y un artista puede representar muchos movimientos.

En TypeScript, la clase MovementEntity tendrá la siguiente definición del atributo artists:

...
   @ManyToMany(() => ArtistEntity, artist => artist.movements)
   @JoinTable()
   artists: ArtistEntity[];

...

Este atributo se encuentra anotado con @JoinTable; lo que indica esta anotación, como se mencionó anteriormente, es que la clase MovementEntity es la dueña de la asociación. Esto significa que un movimiento agregará a los artistas y no al contrario.

Implementación Completa

Para resumir, a continuación tenemos la implementación completa de la clase Movement.

/* eslint-disable prettier/prettier */
/* archivo: src/movement/movement.entity.ts */
import { ArtistEntity } from "../artist/artist.entity";
import { Column, Entity, JoinTable, ManyToMany, PrimaryGeneratedColumn } from "typeorm";

@Entity()
export class MovementEntity {
   @PrimaryGeneratedColumn("uuid")
   id: string;
   @Column()
   name: string;
   @Column()
   description: string;
 
   @Column()
   countryOfOrigin: string;

   @ManyToMany(() => ArtistEntity, artist => artist.movements)
   @JoinTable()
   artists: ArtistEntity[];
}
/* archivo: src/movement/movement.entity.ts */

En este punto, ya no debe existir ningún error de importación en ninguna de las entidades creadas, ya que ya hemos creado todas las clases de la aplicación.

TypeORM se encargará de la creación de las tablas; no obstante se requieren algunas configuraciones adicionales.

Lo primero es verificar que en el módulo principal src/app.module.ts se estén importando todos los módulos creados.

Abra el archivo src/app.module.ts y revise que en el arreglo imports estén incluidos los siguientes módulos:

imports: [MuseumModule, ExhibitionModule, ArtworkModule, SponsorModule, ImageModule, ArtistModule, MovementModule]

Luego importe y configure el módulo TypeORM para indicarle cuáles son las entidades que se persistirán en la base de datos. Para esto, en el mismo archivo src/app.module.ts agregue lo siguiente al arreglo imports:

imports: [MuseumModule, ExhibitionModule, ArtworkModule, SponsorModule, ImageModule, ArtistModule, MovementModule,
   TypeOrmModule.forRoot({
     type: 'postgres',
     host: 'localhost',
     port: 5432,
     username: 'postgres',
     password: 'postgres',
     database: 'museum',
     entities: [ArtistEntity, ArtworkEntity, ExhibitionEntity, ImageEntity, MovementEntity, MuseumEntity, SponsorEntity],
     dropSchema: true,
     synchronize: true,
     keepConnectionAlive: true
   }),
 ],

Acá estamos indicando que para la persistencia se usará una base de datos postgres, la cual se ejecuta en localmente (localhost) en el puerto 5432. El usuario y la contraseña de la base de datos es "postgres" y el nombre de la base de datos es "museum". Las entidades que se persistirán son las relacionadas en el arreglo entities. Si por alguna razón en la instalación de Postgres usted usó otro nombre de usuario y contraseña deberá actualizar los valores correspondientes en este archivo.

Este es el contenido completo del archivo src/app.module.ts:

/* eslint-disable prettier/prettier */
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MuseumModule } from './museum/museum.module';
import { ExhibitionModule } from './exhibition/exhibition.module';
import { ArtworkModule } from './artwork/artwork.module';
import { SponsorModule } from './sponsor/sponsor.module';
import { ArtistModule } from './artist/artist.module';
import { MovementModule } from './movement/movement.module';
import { ImageModule } from './image/image.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ArtistEntity } from './artist/artist.entity';
import { ArtworkEntity } from './artwork/artwork.entity';
import { ExhibitionEntity } from './exhibition/exhibition.entity';
import { ImageEntity } from './image/image.entity';
import { MovementEntity } from './movement/movement.entity';
import { MuseumEntity } from './museum/museum.entity';
import { SponsorEntity } from './sponsor/sponsor.entity';

@Module({
 imports: [MuseumModule, ExhibitionModule, ArtworkModule, SponsorModule, ImageModule, ArtistModule, MovementModule,
   TypeOrmModule.forRoot({
     type: 'postgres',
     host: 'localhost',
     port: 5432,
     username: 'postgres',
     password: 'postgres',
     database: 'museum',
     entities: [ArtistEntity, ArtworkEntity, ExhibitionEntity, ImageEntity, MovementEntity, MuseumEntity, SponsorEntity],
     dropSchema: true,
     synchronize: true,
     keepConnectionAlive: true
   }),
 ],
 controllers: [AppController],
 providers: [AppService],
})
export class AppModule {}

Abra el programa PgAdmin 4, el cual debió instalarse junto con Postgres. Cree una base de datos denominada museum y verifique que está asignada al usuario postgres.

Luego desde la terminal de VS Code instale la dependencia para Postgres usando el comando npm install pg --save.

Finalmente se recomienda parar el servidor de nest.js presionando la combinación de teclas CTRL + C en la terminal de VS Code. Ejecute el servidor nuevamente, y si todo está correcto deberá aparecer el siguiente mensaje en la terminal:

Ahora, vaya de nuevo a PgAdmin, refresque la página y en la base de datos museum deberá aparecer el schema public con las siguientes tablas: