Skip to content

Instantly share code, notes, and snippets.

@kooooohe
Last active February 13, 2024 23:31
Show Gist options
  • Save kooooohe/28a50823f94a2360e3001cc519bc3c29 to your computer and use it in GitHub Desktop.
Save kooooohe/28a50823f94a2360e3001cc519bc3c29 to your computer and use it in GitHub Desktop.
Clean Architecture with InversifyJS
import { firestore } from 'firebase'
import { injectable, inject, Container } from 'inversify'
import { db } from '@/plugins/firebase'
import 'reflect-metadata'
class RestaurantDataModel {
constructor(init: any) {
this.id = init.id || this.id
this.clientUID = init.clientUID || this.clientUID
this.content = init.content || this.content
this.status = init.status || this.status
this.tags = init.tags || this.tags
this.name = init.name || this.name
}
readonly id: string = ''
readonly clientUID: string | null = null
readonly content: string | null = null
readonly status: string | null = null
readonly tags: string[] | null = null
readonly name: string | null = null
}
class RestaurantEntity {
constructor(init: any) {
this.id = init.id || this.id
this.clientUID = init.clientUID || this.clientUID
this.content = init.content || this.content
this.status = init.status || this.status
this.tags = init.tags || this.tags
this.name = init.name || this.name
}
readonly id: string = ''
readonly clientUID: string | null = null
readonly content: string | null = null
readonly status: string | null = null
readonly tags: string[] | null = null
readonly name: string | null = null
}
const TYPES = {
IResutaurantUseCasae: Symbol.for('IResutaurantUseCasae'),
IRestaurantRepository: Symbol.for('IRestaurantRepository'),
RestaurantController: Symbol.for('RestaurantController'),
}
interface IResutaurantUseCasae {
Handle(request: RestaurantGetRequest): Promise<RestaurantEntity[]>
}
class RestaurantGetRequest {
public tags: string[] = []
public limit: number = 0
constructor(tags: string[], limit: number) {
this.tags = tags
this.limit = limit
}
} interface IRestaurantRepository {
GetByTags(tags: string[], limit: number): Promise<RestaurantEntity[]>
}
@injectable()
class RestaurantRepository implements IRestaurantRepository {
private readonly db!: firestore.Firestore
private readonly collectionPath: string = 'public/v1/restaurants'
constructor(connection: firestore.Firestore = db) {
this.db = connection
}
public async GetByTags(
tags: string[],
limit: number
): Promise<RestaurantEntity[]> {
const docs = await this.db.collection(this.collectionPath).limit(limit).get()
const restaurants: RestaurantEntity[] = []
docs.forEach((doc) => {
const restaurant = doc.data()
const dataModel = new RestaurantDataModel(restaurant)
restaurants.push(new RestaurantEntity(dataModel))
})
return restaurants
}
}
@injectable()
class RestaurantGetInteractor implements IResutaurantUseCasae {
private readonly restaurantRepository: IRestaurantRepository
constructor(
@inject(TYPES.IRestaurantRepository) restaurantRepository: IRestaurantRepository
) {
this.restaurantRepository = restaurantRepository
}
Handle(request: RestaurantGetRequest): Promise<RestaurantEntity[]> {
const tags = request.tags
const res = this.restaurantRepository.GetByTags(tags, 1)
return res
}
}
@injectable()
class RestaurantController {
private readonly usecase: IResutaurantUseCasae
constructor(@inject(TYPES.IResutaurantUseCasae) usecase: IResutaurantUseCasae) {
this.usecase = usecase
}
Get(tags: string[], limit: number) {
const request = new RestaurantGetRequest(tags, limit)
const res = this.usecase.Handle(request)
return res
}
}
// move inversify.config.ts
const myContainer = new Container()
myContainer
.bind<IResutaurantUseCasae>(TYPES.IResutaurantUseCasae)
.to(RestaurantGetInteractor)
myContainer.bind<IRestaurantRepository>(TYPES.IRestaurantRepository).to(RestaurantRepository)
myContainer.bind<RestaurantController>(TYPES.RestaurantController).to(RestaurantController)
const restaurantController = myContainer.get<RestaurantController>(TYPES.RestaurantController)
export { restaurantController }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment