Skip to content

Commit

Permalink
added Currency entity; added Swagger
Browse files Browse the repository at this point in the history
  • Loading branch information
geka-evk committed Aug 27, 2023
1 parent 544103d commit 5ecfd03
Show file tree
Hide file tree
Showing 13 changed files with 183 additions and 20 deletions.
5 changes: 3 additions & 2 deletions .env
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# !just for testing purposes. The .env file should be removed from git
HTTP_PORT=3000

#DB_HOST=localhost # for running locally
DB_HOST=postgres
DB_HOST=localhost # for running locally
#DB_HOST=postgres
DB_PORT=5432
DB_USERNAME=curex
DB_PASSWORD=dbpassword
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ DB_NAME=curex-db
DB_SYNCHRONIZE=true
```

## API docs (Swagger)
Url to try existing endpoints: `localhost:3000/api-docs`


## Answers

Expand Down Expand Up @@ -71,4 +74,3 @@ DB_SYNCHRONIZE=true
https://i.imgur.com/yKvgJcy.png



1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ services:
- "${DB_PORT}:5432"
volumes:
- pgData:/var/lib/postgresql/data
- ./src/config/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- curex-net

Expand Down
5 changes: 2 additions & 3 deletions nest-cli.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"collection": "@nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"deleteOutDir": true
},
"assets": ["**/db/file-importer/*.txt"]
"plugins": ["@nestjs/swagger"]
}
}
60 changes: 57 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@nestjs/config": "^3.0.0",
"@nestjs/core": "^9.0.0",
"@nestjs/platform-express": "^9.0.0",
"@nestjs/swagger": "^7.1.8",
"@nestjs/typeorm": "^10.0.0",
"pg": "^8.11.3",
"reflect-metadata": "^0.1.13",
Expand Down
10 changes: 8 additions & 2 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import { pgDbConfig } from './config';
import { DbModule } from './db/db.module';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { Country, Exchange, ExchangeOffice, Rate } from './db/entities';
import {
Country,
Currency,
Exchange,
ExchangeOffice,
Rate,
} from './db/entities';

@Module({
imports: [
Expand All @@ -17,7 +23,7 @@ import { Country, Exchange, ExchangeOffice, Rate } from './db/entities';
}),
TypeOrmModule.forRoot({
...pgDbConfig(),
entities: [Country, ExchangeOffice, Exchange, Rate],
entities: [Country, ExchangeOffice, Exchange, Rate, Currency],
}),
],
controllers: [AppController],
Expand Down
19 changes: 19 additions & 0 deletions src/config/init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = 'curex-db') THEN
CREATE DATABASE "curex-db";
END IF;
END $$;

CREATE TABLE currency (
id serial PRIMARY KEY,
code character varying(3) UNIQUE NOT NULL,
title character varying(50) NOT NULL
);

INSERT INTO currency (code, title) VALUES
('USD', 'United States Dollar'),
('EUR', 'Euro'),
('AUD', 'Australian Dollar'),
('UAH', 'Ukrainian Hryvnia'),
('CAD', 'Canadian Dollar');
5 changes: 4 additions & 1 deletion src/db/db-import.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
countriesField,
exchangeOfficesField,
} from './file-importer/types';
import { ImportResponseDto } from './io.dto';

@Injectable()
export class DbImportService {
Expand All @@ -36,7 +37,9 @@ export class DbImportService {
return this.storeFileContentInDb(content);
}

private async storeFileContentInDb(content: TJsonContent) {
private async storeFileContentInDb(
content: TJsonContent,
): Promise<ImportResponseDto> {
if (!content) {
this.logger.warn(`No content for storing in DB`);
return {
Expand Down
20 changes: 17 additions & 3 deletions src/db/db.controller.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,43 @@
import {
Controller,
Get,
Get, HttpCode,
Post,
Query,
UploadedFile,
UseInterceptors,
} from '@nestjs/common';
import { ApiBody, ApiConsumes, ApiQuery, ApiTags } from '@nestjs/swagger';
import { FileInterceptor } from '@nestjs/platform-express';
import { Express } from 'express';

import { fileUploadOptions } from '../config';
import { DbImportService } from './db-import.service';
import { FileUploadDto, ImportResponseDto } from './io.dto';

@ApiTags('import')
@Controller('db')
export class DbController {
constructor(private readonly dbImportService: DbImportService) {}

@Get('import')
async import(@Query('filename') fileName?: string) {
@ApiQuery({ name: 'filename', required: false })
async import(
@Query('filename') fileName?: string,
): Promise<ImportResponseDto> {
return this.dbImportService.importFileFromDiskToDb(fileName);
}

@Post('import-file')
@HttpCode(200)
@UseInterceptors(FileInterceptor('file', fileUploadOptions))
async handleFileImport(@UploadedFile() file: Express.Multer.File) {
@ApiConsumes('multipart/form-data')
@ApiBody({
description: 'File to import',
type: FileUploadDto,
})
async handleFileImport(
@UploadedFile() file: Express.Multer.File,
): Promise<ImportResponseDto> {
return this.dbImportService.uploadFileToDb(file.buffer.toString());
}
}
50 changes: 45 additions & 5 deletions src/db/entities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,58 +7,94 @@ import {
ManyToOne,
JoinColumn,
} from 'typeorm';
import { ApiProperty } from '@nestjs/swagger';

export type Currencies = 'CAD' | 'AUD' | 'EUR' | 'UAH' | 'USD';
export type TCurrencies = 'CAD' | 'AUD' | 'EUR' | 'UAH' | 'USD';

@Entity()
export class Currency {
@PrimaryGeneratedColumn()
id: number;

@ApiProperty()
@Column({
unique: true,
length: 3,
})
code: TCurrencies;

@Column({ length: 50 })
title: string;
}

abstract class CommonRateExchangeInfo {
@PrimaryGeneratedColumn()
id: number;

@Column({ length: 3 })
from: Currencies;
@ApiProperty({ type: String })
@ManyToOne(() => Currency, (cur) => cur.code)
@JoinColumn({
name: 'from',
referencedColumnName: 'code',
})
from: Currency;

@Column({ length: 3 })
to: Currencies;
@ApiProperty({ type: String })
@ManyToOne(() => Currency, (cur) => cur.code)
@JoinColumn({
name: 'to',
referencedColumnName: 'code',
})
to: Currency;

@ApiProperty()
@Column()
date: Date;
}

@Entity()
export class Country {
@ApiProperty()
@PrimaryGeneratedColumn()
id: number;

@ApiProperty()
@Column({
unique: true,
length: 3,
})
code: string;

@ApiProperty()
@Column({ length: 50 })
name: string;
}

@Entity()
export class ExchangeOffice {
@ApiProperty()
@PrimaryColumn()
id: number;

@ApiProperty()
@Column({ length: 100 })
name: string;

@ApiProperty()
@ManyToOne(() => Country, (c) => c.code, { nullable: false })
@JoinColumn({
name: 'country',
referencedColumnName: 'code',
})
country: Country;

@ApiProperty({ type: () => [Exchange] })
@OneToMany(() => Exchange, (exchange) => exchange.exchangeOffice, {
cascade: true,
})
exchanges: Exchange[];

@ApiProperty({ type: () => [Rate] })
@OneToMany(() => Rate, (rate) => rate.exchangeOffice, {
cascade: true,
})
Expand All @@ -68,6 +104,7 @@ export class ExchangeOffice {

@Entity()
export class Exchange extends CommonRateExchangeInfo {
@ApiProperty()
@Column('float')
ask: number;

Expand All @@ -80,12 +117,15 @@ export class Exchange extends CommonRateExchangeInfo {

@Entity()
export class Rate extends CommonRateExchangeInfo {
@ApiProperty()
@Column('float')
in: number;

@ApiProperty()
@Column('float')
out: number;

@ApiProperty()
@Column('float')
reserve: number;

Expand Down
Loading

0 comments on commit 5ecfd03

Please sign in to comment.