-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature #6 - add domain, business and adaters of get products function
- Loading branch information
1 parent
9223996
commit 558934c
Showing
16 changed files
with
461 additions
and
1 deletion.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { CurrencyEnum } from '../../2-business/enums/currencyEnum' | ||
|
||
export interface Product { | ||
category: string | ||
id: number | ||
name: string | ||
price: number | ||
promotionalPrice: number | ||
rating: number | ||
colors: string[] | ||
currency: CurrencyEnum | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { CurrencyEnum } from '../../enums/currencyEnum' | ||
import { ProductCategoryEnum } from '../../enums/productCategory' | ||
|
||
export interface GetProductsInputDto { | ||
category: ProductCategoryEnum | ||
baseCurrency: CurrencyEnum | ||
targetCurrency?: CurrencyEnum | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export enum ProductCategoryEnum { | ||
CASUAL_SHOES = 'shoes', | ||
CASUAL_SHIRT = 'shirt', | ||
SOCCER = 'soccer' | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { Product } from '../../1-domain/entities/product' | ||
import { CurrencyEnum } from '../enums/currencyEnum' | ||
import { ProductCategoryEnum } from '../enums/productCategory' | ||
|
||
export interface IProductRepository { | ||
getByCategoryAndCurrency (category: ProductCategoryEnum, baseCurrency: CurrencyEnum): Promise<Product[]> | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { ExchangeRate } from '../../1-domain/entities/exchangeRate' | ||
import { CurrencyEnum } from '../../2-business/enums/currencyEnum' | ||
|
||
export interface IExchangeRateInternalService { | ||
get (base: CurrencyEnum): Promise<ExchangeRate> | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { IExchangeRateInternalService } from '../../services/iExchangeRateInternalService' | ||
import { IProductRepository } from '../../repositories/iProductRepository' | ||
import { GetProductsInputDto } from '../../dto/product/getProductstInputDto' | ||
import { Product } from '../../../1-domain/entities/product' | ||
import { CurrencyEnum } from '../../enums/currencyEnum' | ||
|
||
export class GetProductsUseCase { | ||
|
||
constructor ( | ||
private readonly productRepository: IProductRepository, | ||
private readonly exchangeRateInternalService: IExchangeRateInternalService | ||
) {} | ||
|
||
private logPrefix: string = 'GetExchangeRateUseCase' | ||
|
||
async execute (input: GetProductsInputDto): Promise<Product[]> { | ||
console.log(`${this.logPrefix} :: start`) | ||
try { | ||
const { category, baseCurrency, targetCurrency } = input | ||
let products: Product[] = await this.productRepository.getByCategoryAndCurrency(category, baseCurrency) | ||
|
||
console.log(`${this.logPrefix} ::`, { products }) | ||
|
||
products = await this.calculatePriceByLatestCurrentExchangeRate(products, baseCurrency, targetCurrency) | ||
|
||
console.log(`${this.logPrefix} :: products with currency updated ::`, { products }) | ||
console.log(`${this.logPrefix} :: end`) | ||
|
||
return products | ||
} catch (error) { | ||
throw error | ||
} | ||
} | ||
|
||
private async calculatePriceByLatestCurrentExchangeRate (products: Product[], originCurrency: CurrencyEnum, targetCurrency: CurrencyEnum | undefined): Promise<Product[]> { | ||
const exchangeRate = await this.exchangeRateInternalService.get(originCurrency) | ||
console.log('calculatePriceByLatestCurrentExchangeRate ::', { exchangeRate }) | ||
|
||
const targetCurrencyExchangeRate = exchangeRate.rates[targetCurrency || originCurrency] | ||
|
||
return products.map(product => { | ||
return { | ||
...product, | ||
price: product.price * targetCurrencyExchangeRate, | ||
promotionalPrice: product.promotionalPrice * targetCurrencyExchangeRate | ||
} | ||
}) | ||
} | ||
} | ||
|
||
export default GetProductsUseCase |
47 changes: 47 additions & 0 deletions
47
src/3-adapters/controller/product/getProductsController.ts
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { ControllerBase } from '../../controllerBase' | ||
import { Output } from '../../../2-business/dto/output' | ||
import { InputGetProducts } from '../../serializers/product/getProducts/input' | ||
import { OutputGetProducts } from '../../serializers/product/getProducts/output' | ||
import { IProductRepository } from '../../../2-business/repositories/iProductRepository' | ||
import { IExchangeRateInternalService } from '../../../2-business/services/iExchangeRateInternalService' | ||
import { GetProductsUseCase } from '../../../2-business/useCases/product/getProductsUseCase' | ||
import { Product } from '../../../1-domain/entities/product' | ||
|
||
export class GetProductsController extends ControllerBase<InputGetProducts, OutputGetProducts> { | ||
constructor ( | ||
private readonly productRepository: IProductRepository, | ||
private readonly exchangeRateInternalService: IExchangeRateInternalService | ||
) { super() } | ||
|
||
async run (input: InputGetProducts): Promise<Output<OutputGetProducts>> { | ||
const logPrefix = 'GetProductsController' | ||
console.log(`${logPrefix} :: start`) | ||
console.log(`${logPrefix} ::`, input) | ||
|
||
try { | ||
const getProductsUseCase = new GetProductsUseCase( | ||
this.productRepository, | ||
this.exchangeRateInternalService | ||
) | ||
|
||
const products: Product[] = await getProductsUseCase.execute(input) | ||
|
||
console.log(`${logPrefix} :: end`) | ||
|
||
return { | ||
httpCode: 200, | ||
status: 'success', | ||
data: { products } | ||
} | ||
|
||
} catch (error) { | ||
console.error(error) | ||
|
||
return { | ||
httpCode: 400, | ||
status: 'error', | ||
message: 'general error' | ||
} | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { InputClassValidator } from '../../../../4-framework/utility/classValidator' | ||
import { IsNotEmpty, IsOptional, IsString } from 'class-validator' | ||
import { CurrencyEnum } from '../../../../2-business/enums/currencyEnum' | ||
import { ProductCategoryEnum } from '../../../../2-business/enums/productCategory' | ||
|
||
export class InputGetProducts extends InputClassValidator { | ||
@IsNotEmpty() | ||
@IsString() | ||
category!: ProductCategoryEnum | ||
|
||
@IsNotEmpty() | ||
@IsString() | ||
baseCurrency!: CurrencyEnum | ||
|
||
@IsOptional() | ||
@IsString() | ||
targetCurrency?: CurrencyEnum | ||
|
||
constructor (obj: Partial<InputGetProducts>) { | ||
super() | ||
Object.assign(this, obj) | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { Product } from '../../../../1-domain/entities/product' | ||
|
||
export interface OutputGetProducts { | ||
products: Product[] | ||
} |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
getProducts: | ||
handler: ${self:custom.funcDir}/product/getProducts.handler | ||
vpc: | ||
securityGroupIds: | ||
- sg-0cd52ea46933db116 | ||
subnetdIds: | ||
- subnet-05d245e39491bb3d2 | ||
- subnet-06761316782230c98 | ||
events: | ||
- http: | ||
method: GET | ||
path: /${self:custom.baseApi}/products |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
'use strict' | ||
|
||
import { APIGatewayEvent } from 'aws-lambda' | ||
import { GetProductsController } from '../../../3-adapters/controller/product/getProductsController' | ||
import { InputGetProducts } from '../../../3-adapters/serializers/product/getProducts/input' | ||
import { ProductRepository } from '../../repositories/productRepository' | ||
import { ExchangeRateInternalService } from '../../services/exchangeRateInternalService' | ||
import { apiGatewayHttpEventNormalizer } from '../../utility/eventAdapters' | ||
|
||
function eventAdapter (event: APIGatewayEvent): InputGetProducts { | ||
const body = apiGatewayHttpEventNormalizer(event) | ||
return new InputGetProducts(body) | ||
|
||
} | ||
|
||
exports.handler = async (event: APIGatewayEvent) => { | ||
const getProductsController = new GetProductsController( | ||
new ProductRepository(), | ||
new ExchangeRateInternalService() | ||
) | ||
|
||
const input = eventAdapter(event) | ||
|
||
const response = await getProductsController.run(input) | ||
|
||
return response | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import dynamoose, { Schema } from 'dynamoose' | ||
import { Document } from 'dynamoose/dist/Document' | ||
import { SchemaDefinition } from 'dynamoose/dist/Schema' | ||
import { Model, ModelOptionsOptional } from 'dynamoose/dist/Model' | ||
import { Product } from '../../../1-domain/entities/product' | ||
|
||
export interface ProductEntity extends Document, Product { } | ||
|
||
const schemaDefinition: SchemaDefinition = { | ||
category: { | ||
type: String, | ||
hashKey: true | ||
}, | ||
id: { | ||
type: String, | ||
rangeKey: true | ||
}, | ||
name: { | ||
type: String, | ||
required: true | ||
}, | ||
price: { | ||
type: Number, | ||
required: true | ||
}, | ||
promotionalPrice: { | ||
type: Number, | ||
required: true | ||
}, | ||
rating: { | ||
type: Number, | ||
required: true | ||
}, | ||
colors: { | ||
type: Array, | ||
required: true | ||
}, | ||
currency: { | ||
type: String, | ||
required: true, | ||
index: { | ||
name: 'CategoryBaseCurrencyIndex', | ||
global: true | ||
} | ||
} | ||
} | ||
|
||
const schema = new Schema(schemaDefinition, { | ||
timestamps: true, | ||
saveUnknown: true | ||
}) | ||
|
||
const modelOptions: ModelOptionsOptional = { | ||
throughput: 'ON_DEMAND', | ||
create: false, | ||
waitForActive: false | ||
} | ||
|
||
export const ProductModel: Model<ProductEntity> = | ||
dynamoose.model('Product', schema, modelOptions) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { ExchangeRate } from '../../1-domain/entities/exchangeRate' | ||
import { ExchangeRateModel } from '../models/dynamo/exchangeRate' | ||
import { IExchangeRateRepository } from '../../2-business/repositories/iExchangeRateRepository' | ||
import { CurrencyEnum } from '../../2-business/enums/currencyEnum' | ||
import { IProductRepository } from '../../2-business/repositories/iProductRepository' | ||
import { Product } from '../../1-domain/entities/product' | ||
import { ProductCategoryEnum } from '../../2-business/enums/productCategory' | ||
import { ProductModel } from '../models/dynamo/product' | ||
|
||
export class ProductRepository implements IProductRepository { | ||
getByCategoryAndCurrency (category: ProductCategoryEnum, baseCurrency: CurrencyEnum): Promise<Product[]> { | ||
return ProductModel.query('category').eq(category).where('currency').eq(baseCurrency).exec() | ||
} | ||
} |
Oops, something went wrong.