Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/fabioformosa/metamorphosis-nestjs
Conversion service for NestJs Framework
https://github.com/fabioformosa/metamorphosis-nestjs
conversion-service converters dto nestjs typegoose
Last synced: 3 months ago
JSON representation
Conversion service for NestJs Framework
- Host: GitHub
- URL: https://github.com/fabioformosa/metamorphosis-nestjs
- Owner: fabioformosa
- License: mit
- Created: 2019-10-15T15:35:48.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2023-01-04T22:46:33.000Z (about 2 years ago)
- Last Synced: 2024-10-12T18:21:24.360Z (3 months ago)
- Topics: conversion-service, converters, dto, nestjs, typegoose
- Language: TypeScript
- Homepage:
- Size: 471 KB
- Stars: 32
- Watchers: 1
- Forks: 5
- Open Issues: 20
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
[![Build Status](https://travis-ci.org/fabioformosa/metamorphosis-nestjs.svg?branch=master)](https://travis-ci.org/fabioformosa/metamorphosis-nestjs)
[![Coverage Status](https://coveralls.io/repos/github/fabioformosa/metamorphosis-nestjs/badge.svg?branch=master)](https://coveralls.io/github/fabioformosa/metamorphosis-nestjs?branch=master) [![NPM](https://nodei.co/npm/@fabio.formosa/metamorphosis-nest.png?mini=true)](https://npmjs.org/package/@fabio.formosa/metamorphosis-nest)# METAMORPHOSIS-NESTJS
> "Nothing is lost, nothing is created, everything is transformed"
> _Lavoisier**Metamorphosis-NestJS** is the NodeJS version of [**Metamorphosis**](https://fabioformosa.github.io/metamorphosis), an utility library to ease conversions of objects, provided as java, javascript and NestJS as well.
Metamorphosis-NestJS has been adapted to the popular framework [NestJS](https://nestjs.com), so it exports a conversion service, that you can import and use into your application as hub of all convertions: for example, entities to DTOs and/or viceversa
![Red Chameleon - ph. George Lebada - pexels.com!](https://images.pexels.com/photos/567540/pexels-photo-567540.jpeg?auto=compress&cs=tinysrgb&h=325&w=470 "Red Chameleon - ph. George Lebada - pexels.com")
## QUICK START
### INSTALL
`npm install --save @fabio.formosa/metamorphosis-nest`### IMPORT MODULE
```
import { MetamorphosisNestModule } from '@fabio.formosa/metamorphosis-nest';@Module({
imports: [MetamorphosisModule.register()],
...
}
export class MyApp{
}
```### NEW CONVERTER
Create a new converter class, implementing the interface `Converter` and decorate the class with `@Convert`
```
import { Convert, Converter } from '@fabio.formosa/metamorphosis';@Injectable()
@Convert(Car, CarDto)
export default class CarToCarDtoConverter implements Converter {
public convert(source: Car): CarDto {
const target = new CarDto();
target.color = source.color;
target.model = source.model;
target.manufacturerName = source.manufacturer.name;
return target;
}}
```
In the above example, the converter is `@Injectable()`, so is a NestJs Service.### USE CONVERSION SERVICE
When your converters are instanciated by NestJs, they will be registered into the `conversion service`.
The `conversion service` is the hub for all conversions. You can inject it and invoke the convert method.```
import { ConversionService } from '@fabio.formosa/metamorphosis-nest';@Injectable()
class CarService{constructor(private convertionService: ConvertionService){}
public async getCar(id: string): CarDto{
const car: Car = await CarModel.findById(id);
return await this.convertionService.convert(car, CarDto);
}}
```## ADVANCED FEATURES
### CONVERT ARRAYS
```
const cars: Car[] = ...
const carDtos = await this.convertionService.convertAll(cars, CarDto);
```### ASYNC CONVERSIONS
If your converter must be async (_eg. it must retrieve entities from DB_):
```
@Injectable()
@Convert(PlanetDto, Planet)
export default class PlanetDtoToPlanet implements Converter> {
async convert(source: PlanetDto): Promise {
...
}}
```
* Define Planet as target type in `@Convert`
* declare `Promise` in `Converter interface`.
* The convert method will be `async`.When you invoke conversionService you must apply `await` if you know for that conversion is returned a `Promise`.
```
const planet = await conversionService.convert(planetDto, Planet);
```or in case of conversion of an array:
```
const planets = await Promise.all(conversionService.convert(planetDto, Planet));
```### TYPEGOOSE SUPPORT
If you have to convert mongoose document into DTO, it's recommended to use [Typegoose](https://https://github.com/typegoose/typegoose) and [class-transformer](https://github.com/typestack/class-transformer).1. Add dependency:
```
npm install --save @fabio.formosa/metamorphosis-typegoose-plugin
```1. Register conversion service with `metamorphosis-typegoose-plugin`
```
import { MetamorphosisNestModule } from '@fabio.formosa/metamorphosis-nest';
import TypegoosePlugin from '@fabio.formosa/metamorphosis-typegoose-plugin/dist/typegoose-plugin';
import { MetamorphosisPlugin } from '@fabio.formosa/metamorphosis';const typegoosePlugin = new TypegoosePlugin();
@Module({
imports: [MetamorphosisModule.register({logger: false, plugins: [typegoosePlugin])],
...
}
export class MyApp{
}
```1. Define the type of your model and the moongose schema using decorators (`@prop`). (note: team is annotate by `@Type` decorator provided by class-transformer in order to use `plainToClass` function)
```
@modelOptions({
existingMongoose: mongoose,
collection: 'players'
})
class Player{
_id: ObjectID;@prop({require : true})
name: string;
@prop()
score: number;
@Type(() => Team)
@prop({require : true})
team: Team;
}class Team{
_id: ObjectID;
@prop({require : true})
name: string;
@prop({require : true})
city: string;
}```
1. Define your DTOs```
class PlayerDto{
id: string;
name: string;
team: string;
}class TeamDto{
id: string;
name: string;
city: string;
}
```1. Create converters
```
import {Converter, Convert} from '@fabio.formosa/metamorphosis';@Convert(Player, PlayerDto)
class PlayerConverterTest implements Converter {
public convert(source: Player): PlayerDto {
const target = new PlayerDto();
target.id = source._id.toString();
target.name = source.name;
target.team = source.team.name;
return target;
}}
@Convert(Team, TeamDto)
class TeamConverterTest implements Converter {
public convert(source: Team): TeamDto {
const target = new TeamDto();
target.id = source._id.toString();
target.name = source.name;
target.city = source.city;
return target;
}}
```
1. Use ConversionService
```
import {ConversionService} from '@fabio.formosa/metamorphosis-nest';@Injectable()
class MyService{constructor(private readonly ConversionService conversionService){}
doIt(){
const foundPlayerModel = await PlayerModel.findOne({'name': 'Baggio'}).exec() || player;const playerDto = await this.conversionService.convert(foundPlayerModel, PlayerDto);
//if you want convert only the team (and not also the Player)
const teamDto = await conversionService.convert(foundPlayer.team, TeamDto);
}
```### TYPEORM EXAMPLE
typeORM is supported by metamorphosis. Following an example (it doesn't show the converter because it's trivial, if you read above the doc):
```
let product = new Product();
product.name = 'smartphone';
product.pieces = 50;const productRepository = connection.getRepository(Product);
product = await productRepository.save(product);const productDto: ProductDto = await conversionService.convert(product, ProductDto);
```or if your entity extends `BaseEntity`
```
let product = new Product();
product.name = 'smartphone';
product.pieces = 50;
product = await product.save(product);const productDto: ProductDto = await conversionService.convert(product, ProductDto);
```In case of conversion from DTO to entity:
```
@Injectable()
@Convert(ProductDto, Product)
export default class ProductDtoConverterTest implements Converter> {constructor(private readonly connection: Connection){}
public async convert(source: ProductDto): Promise {
const productRepository: Repository = this.connection.getRepository(Product);
const target: Product | undefined = await productRepository.findOne(source.id);
if(!target)
throw new Error(`not found any product by id ${source.id}`);
target.name = source.name;
return target;
}}
```### DEBUG MODE
To activate debug mode
```
import { MetamorphosisNestModule } from '@fabio.formosa/metamorphosis-nest';@Module({
imports: [MetamorphosisModule.register({logger: true})],
...
}
export class MyApp{
}
```
In this case, metamorphosis will send log to console. Otherwise, you can pass a custom debug function `(msg: string) => void` , e.g:
```
import { MetamorphosisNestModule } from '@fabio.formosa/metamorphosis-nest';const myCustomLogger = {
debug: (msg: string) => {
winston.logger(msg); //example
}
}@Module({
imports: [MetamorphosisModule.register({logger: myCustomLogger.debug})],
...
}
export class MyApp{
}
```At the moment, MetamorphosisNestModule uses console to log.
Soon, it will be possible to pass a custom logger.## REQUIREMENTS
* TypeScript 3.2+
* Node 8, 10+
* emitDecoratorMetadata and experimentalDecorators must be enabled in tsconfig.json## CREDITS
Red Chameleon in this README file is a picture of ph. George Lebada (pexels.com)