Created
March 30, 2020 17:53
-
-
Save Roms1383/c2b190677796d389b4d33350c06c80ce to your computer and use it in GitHub Desktop.
Medium - Combining decorators for easy data manipulation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Note } from '@kroms/notes/notes.entity' | |
import { NotesModule } from '@kroms/notes/notes.module' | |
import { User } from '@kroms/notes/users.entity' | |
import { INestApplication, Injectable, Module } from '@nestjs/common' | |
import { NestFactory } from '@nestjs/core' | |
import { | |
InjectRepository, | |
TypeOrmModule, | |
TypeOrmModuleOptions, | |
} from '@nestjs/typeorm' | |
import * as chalk from 'chalk' | |
import Axios from 'axios' | |
import { Repository } from 'typeorm' | |
import * as generate from './seed' | |
require('dotenv').config() | |
const HOST = process.env.SERVER_HOST || 'localhost' | |
const PORT = +process.env.SERVER_PORT || 3000 | |
const options: TypeOrmModuleOptions = { | |
type: (process.env.TYPEORM_CONNECTION as 'mariadb') || 'mysql' || 'mariadb', | |
host: process.env.TYPEORM_HOST || 'localhost', | |
port: +process.env.TYPEORM_PORT || 3306, | |
username: process.env.TYPEORM_USERNAME || 'root', | |
password: process.env.TYPEORM_PASSWORD || 'root', | |
database: process.env.TYPEORM_DATABASE || 'test_nestjs_decorators', | |
entities: [User, Note], | |
synchronize: true, | |
dropSchema: true, | |
} | |
const COUNT_USERS = 3 | |
const COUNT_NOTES = 5 | |
let users | |
let notes | |
@Injectable() | |
class SeederService { | |
constructor( | |
@InjectRepository(User) private readonly users_repo: Repository<User>, | |
@InjectRepository(Note) private readonly notes_repo: Repository<Note>, | |
) {} | |
public async seed(): Promise<void> { | |
const generatedUsers = generate.users(COUNT_USERS).slice() | |
const { generatedMaps: usersIds } = await this.users_repo.manager.connection | |
.createQueryBuilder() | |
.insert() | |
.into(User) | |
.values(generatedUsers) | |
.execute() | |
users = usersIds | |
.map(({ id }, index) => ({ id, ...generatedUsers[index] })) | |
.slice() | |
const generatedNotes = generate.notes(COUNT_NOTES, users).slice() | |
const { generatedMaps: notesIds } = await this.notes_repo.manager.connection | |
.createQueryBuilder() | |
.insert() | |
.into(Note) | |
.values(generatedNotes) | |
.execute() | |
notes = notesIds | |
.map(({ id }, index) => ({ id, ...generatedNotes[index] })) | |
.slice() | |
// console.info(chalk.green('seeded', '\n', '-----')); | |
// console.info(users); | |
// console.info(notes); | |
} | |
} | |
@Module({ | |
imports: [TypeOrmModule.forRoot(options), NotesModule], | |
providers: [SeederService], | |
}) | |
class AppModule {} | |
const bootstrap = async (): Promise<INestApplication> => { | |
const app = await NestFactory.create(AppModule) | |
const seeder = app.get(SeederService) | |
await seeder.seed() | |
await app.listen(PORT) | |
return app | |
} | |
const teardown = async (app: INestApplication): Promise<void> => { | |
await app.close() | |
app = undefined | |
} | |
describe('tests', () => { | |
let app | |
beforeAll(async () => { | |
app = await bootstrap() | |
}) | |
afterAll(async () => { | |
await teardown(app) | |
}) | |
describe('notes', () => { | |
it('can fetch all the notes', async () => { | |
const { data } = await Axios.get(`http://${HOST}:${PORT}/notes`) | |
// console.info(chalk.magenta('received', '\n', '-----')); | |
// console.info(data); | |
expect(data).toBeDefined() | |
expect(data).toHaveLength(COUNT_NOTES) | |
expect(data).toEqual( | |
expect.arrayContaining(notes.map(expect.objectContaining)), | |
) | |
}) | |
}) | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const TIME = 'YYYY-MM-DDTHH:mm:ss.SSSZ' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
CallHandler, | |
ExecutionContext, | |
Injectable, | |
NestInterceptor, | |
} from '@nestjs/common' | |
import { classToPlain } from 'class-transformer' | |
import { Observable } from 'rxjs' | |
import { map } from 'rxjs/operators' | |
@Injectable() | |
export class IOInterceptor implements NestInterceptor { | |
intercept(_context: ExecutionContext, next: CallHandler): Observable<any> { | |
return next.handle().pipe(map(output => classToPlain(output))) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Controller, Get, UseInterceptors } from '@nestjs/common' | |
import * as chalk from 'chalk' | |
import { IOInterceptor } from './io.interceptor' | |
import { Note } from './notes.entity' | |
import { NotesService } from './notes.service' | |
@Controller('notes') | |
@UseInterceptors(IOInterceptor) | |
export class NotesController { | |
constructor(private readonly service: NotesService) {} | |
@Get() | |
async fetch(): Promise<Note[]> { | |
try { | |
const notes = await this.service.fetch() | |
// console.info(chalk.blue('sending back', '\n', '-----')); | |
// console.info(notes); | |
return notes | |
} catch (e) { | |
console.error(e) | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Exclude, Expose, Transform } from 'class-transformer' | |
import { IsDateString, IsUUID } from 'class-validator' | |
import { Moment, utc } from 'moment' | |
import { | |
Column, | |
Entity, | |
JoinColumn, | |
ManyToOne, | |
PrimaryGeneratedColumn, | |
} from 'typeorm' | |
import { TIME } from './constants' | |
import { User } from './users.entity' | |
@Entity() | |
export class Note { | |
@PrimaryGeneratedColumn('uuid') | |
@IsUUID() | |
@Expose() | |
id: string | |
@Column() | |
@Expose() | |
description: string | |
// validation | |
@IsDateString() | |
// from db to class | |
@Column({ | |
type: 'varchar', | |
transformer: { | |
from: value => utc(value), | |
to: value => utc(value).format(TIME), | |
}, | |
}) | |
// from plain to class | |
@Transform(value => utc(value), { toClassOnly: true }) | |
// from class to plain | |
@Transform(value => utc(value).format(TIME), { toPlainOnly: true }) | |
// expose when transformed into plain | |
@Expose() | |
on: Moment | |
@ManyToOne( | |
type => User, | |
user => user.notes, | |
) | |
@JoinColumn({ name: 'owner' }) | |
@Exclude() | |
user: User | |
@Column({ nullable: false }) | |
@Expose() | |
owner: string | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Module } from '@nestjs/common' | |
import { TypeOrmModule } from '@nestjs/typeorm' | |
import { NotesController } from './notes.controller' | |
import { Note } from './notes.entity' | |
import { NotesService } from './notes.service' | |
import { User } from './users.entity' | |
@Module({ | |
imports: [TypeOrmModule.forFeature([User, Note])], | |
providers: [NotesService], | |
controllers: [NotesController], | |
exports: [TypeOrmModule], | |
}) | |
export class NotesModule {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Injectable } from '@nestjs/common' | |
import { InjectRepository } from '@nestjs/typeorm' | |
import { Repository } from 'typeorm' | |
import { Note } from './notes.entity' | |
@Injectable() | |
export class NotesService { | |
constructor( | |
@InjectRepository(Note) private readonly repository: Repository<Note>, | |
) {} | |
async fetch(): Promise<Note[]> { | |
return this.repository.find({ relations: ['user'] }) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Note } from '@kroms/notes/notes.entity' | |
import { User } from '@kroms/notes/users.entity' | |
import * as Chance from 'chance' | |
import * as crypto from 'crypto' | |
import * as moment from 'moment' | |
import { TIME } from '@kroms/notes/constants' | |
const chance = Chance() | |
export const users = (howMany: number): User[] => { | |
const users: User[] = [] | |
let user: User | |
for (let i = 0; i < howMany; i++) { | |
user = new User() | |
user.firstname = chance.first() | |
user.lastname = chance.last() | |
user.email = chance.email() | |
user.password = crypto | |
.createHmac('sha256', 'secret-key') | |
.update('password') | |
.digest('hex') | |
users.push(user) | |
} | |
return users | |
} | |
export const notes = (howMany: number, owners?: User[]): Note[] => { | |
const notes: Note[] = [] | |
let note: Note | |
for (let i = 0; i < howMany; i++) { | |
note = new Note() | |
note.description = chance.sentence({ words: 5 }) | |
note.on = (moment | |
.utc(chance.date({ year: 1983 })) | |
.format(TIME) as unknown) as moment.Moment | |
note.owner = owners[Math.floor(Math.random() * (owners.length - 1))].id | |
notes.push(note) | |
} | |
return notes | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Exclude, Expose, Type } from 'class-transformer' | |
import { IsEmail, IsHash, IsUUID, MinLength } from 'class-validator' | |
import { | |
Column, | |
Entity, | |
PrimaryGeneratedColumn, | |
OneToMany, | |
JoinColumn, | |
} from 'typeorm' | |
import { Note } from './notes.entity' | |
@Entity() | |
export class User { | |
@PrimaryGeneratedColumn('uuid') | |
@IsUUID() | |
@Expose() | |
id: string | |
@Column({ nullable: true }) | |
@MinLength(2) | |
@Expose() | |
firstname?: string | |
@Column({ nullable: true }) | |
@Expose() | |
lastname?: string | |
@Column({ length: 255 }) | |
@IsEmail() | |
@Expose() | |
email!: string | |
@Column() | |
@IsHash('sha256') | |
@Exclude() | |
password: string | |
@Type(() => Note) | |
@OneToMany( | |
type => Note, | |
note => note.owner, | |
) | |
@JoinColumn({ name: 'notes' }) | |
@Exclude() | |
notes?: Note[] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment