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.
Para realizar este tutorial Ud. debe:
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:
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.
Dentro del contexto de la aplicación, un museo tiene los siguientes atributos primitivos:
name
: el nombre del museo.description
: descripción y detalles sobre el museo.address
: la dirección específica del museo.city
: ciudad en donde se encuentra ubicado el museo.image
: una imagen alusiva al museo; este campo es un campo de texto en el que se incluirá una URL que apunte a una imagen (ya sea local o de internet).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:
@Entity():
indica que la clase es una entidad que será mapeada a una tabla en la base de datos.@PrimaryGeneratedColumn:
indica que el atributo id
es la llave primaria de la clase Museum, y que el valor de esta llave se genera automáticamente. A esta anotación se le envía por parámetro el tipo de ID que se usará para la entidad, que en este caso será ‘uuid'.@Column:
indica que el atributo de la clase se mapea a una columna de la tabla en la base de datos..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.
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.
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[];
...
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.
Dentro del contexto de la aplicación, una exhibición tiene los siguientes atributos:
name
: el nombre de la exhibición.description
: descripción y detalles sobre la exhibición.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
.
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.
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;
...
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[];
...
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.
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.
Dentro del contexto de la aplicación una obra de arte tiene los siguientes atributos:
name
: nombre de la obra de arte.year
: año en el que se creó la obra de arte.description
: descripción y detalles de la obra de arte.type
: tipo de obra de artemainImage
: ruta en la que se almacena la imagen principal de la obra de arte.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.
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.
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;
...
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;
...
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[];
...
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;
...
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 */
Dentro del contexto de la aplicación, un artista tiene los siguientes atributos:
name
: el nombre del artista.birthplace
: lugar de nacimiento del artista.birthdate
: fecha de nacimiento del lugar. Este atributo es de tipo Date.image
: ruta en la cual está una fotografía del artista.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;
}
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.
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[];
...
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.
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 */
Dentro del contexto de la aplicación, un patrocinador tiene los siguientes atributos:
name
: el nombre del patrocinador.description
: descripción y detalles sobre el patrocinador.website
: dirección web del patrocinador.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;
}
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.
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;
...
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 */
Dentro del contexto de la aplicación, una Imagen tiene los siguientes atributos:
source
: dirección en la cual se encuentra la imagen.altText
: texto alternativo descriptivo, que se muestra en caso de que no sea posible visualizarse la imagen.height
: alto (en pixeles) de la imagen.width
: ancho (en pixeles) de la imagen.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;
}
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.
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;
...
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 */
Dentro del contexto de la aplicación, un movimiento artístico tiene los siguientes atributos:
name
: el nombre del movimiento.description
: descripción y detalles del movimiento.countryOfOrigin
: país en el que se originó el movimiento.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;
}
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.
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.
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: