From eb71a1ee64ee9241abca0b06030cdf454a60a654 Mon Sep 17 00:00:00 2001 From: Shai Yallin Date: Sun, 12 May 2024 09:20:23 +0300 Subject: [PATCH] added two other varieties of module registration --- packages/server/package.json | 2 +- packages/server/src/adapters/memory.module.ts | 30 ++++++++++ .../server/src/adapters/mongodb.module.ts | 42 +++++++++++++ packages/server/src/adapters/order.repo.ts | 4 +- packages/server/src/adapters/product.repo.ts | 4 +- .../src/{app.module.ts => app.module.ioc.ts} | 4 +- packages/server/src/app.module.overrides.ts | 11 ++++ packages/server/src/app.module.register.ts | 14 +++++ packages/server/src/index.ts | 27 +++++++-- packages/server/src/server.testkit.ts | 59 +++++++++++++++++-- yarn.lock | 11 +++- 11 files changed, 192 insertions(+), 16 deletions(-) create mode 100644 packages/server/src/adapters/memory.module.ts create mode 100644 packages/server/src/adapters/mongodb.module.ts rename packages/server/src/{app.module.ts => app.module.ioc.ts} (91%) create mode 100644 packages/server/src/app.module.overrides.ts create mode 100644 packages/server/src/app.module.register.ts diff --git a/packages/server/package.json b/packages/server/package.json index c8ae834..283ab3c 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -28,7 +28,7 @@ "fastify": "^4.23.2", "fastify-type-provider-zod": "^1.1.9", "mongodb": "^6.1.0", - "nanoid": "^4.0.2", + "nanoid": "^3.3.7", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", "ts-byob": "^1.0.3", diff --git a/packages/server/src/adapters/memory.module.ts b/packages/server/src/adapters/memory.module.ts new file mode 100644 index 0000000..77c96bb --- /dev/null +++ b/packages/server/src/adapters/memory.module.ts @@ -0,0 +1,30 @@ +import {DynamicModule} from "@nestjs/common"; +import {CART_REPO, ORDER_REPO, PRODUCT_REPO} from "./index"; +import {MemoryCartRepository} from "./cart.repo"; +import {InMemoryOrderRepository, InMemoryProductRepository} from "./fake"; +import {ProductTemplate} from "../types"; + + +export class MemoryModule { + static forTests(products: ProductTemplate[]): DynamicModule { + return { + module: MemoryModule, + providers: [ + + { + provide: PRODUCT_REPO, + useValue: new InMemoryProductRepository(products) + }, + { + provide: ORDER_REPO, + useClass: InMemoryOrderRepository, + }, + { + provide: CART_REPO, + useClass: MemoryCartRepository, + } + ], + exports: [PRODUCT_REPO, ORDER_REPO, CART_REPO] + } + } +} \ No newline at end of file diff --git a/packages/server/src/adapters/mongodb.module.ts b/packages/server/src/adapters/mongodb.module.ts new file mode 100644 index 0000000..4e117d8 --- /dev/null +++ b/packages/server/src/adapters/mongodb.module.ts @@ -0,0 +1,42 @@ +import {MongoClient} from "mongodb"; +import {DynamicModule} from "@nestjs/common"; +import {CART_REPO, ORDER_REPO, PRODUCT_REPO} from "./index"; +import {MongoDBProductRepository} from "./product.repo"; +import {MongoDBOrderRepository} from "./order.repo"; +import {MemoryCartRepository} from "./cart.repo"; + +export class MongoDBModule { + static forRoot(uri: string): DynamicModule { + + return { + module: MongoDBModule, + providers: [ + { + provide: "storeDB", + useFactory: async () => { + const mongo = await new MongoClient(uri, { + connectTimeoutMS: 100, + serverSelectionTimeoutMS: 100, + socketTimeoutMS: 100 + }).connect(); + + return mongo.db("store"); + }, + }, + { + provide: PRODUCT_REPO, + useClass: MongoDBProductRepository + }, + { + provide: ORDER_REPO, + useClass: MongoDBOrderRepository, + }, + { + provide: CART_REPO, + useClass: MemoryCartRepository, + } + ], + exports: [PRODUCT_REPO, ORDER_REPO, CART_REPO] + } + } +} \ No newline at end of file diff --git a/packages/server/src/adapters/order.repo.ts b/packages/server/src/adapters/order.repo.ts index 5af2db5..662f362 100644 --- a/packages/server/src/adapters/order.repo.ts +++ b/packages/server/src/adapters/order.repo.ts @@ -1,6 +1,6 @@ import { Collection, Db, ObjectId, WithId } from "mongodb"; import { Order } from "../types"; -import {Injectable} from "@nestjs/common"; +import {Inject, Injectable} from "@nestjs/common"; type MongoOrder = Omit; const docToOrder = ({_id, ...rest}: WithId) => Order.parse({id: _id.toString(), ...rest}); @@ -9,7 +9,7 @@ const docToOrder = ({_id, ...rest}: WithId) => Order.parse({id: _id. export class MongoDBOrderRepository { private orders: Collection; - constructor(db: Db) { + constructor(@Inject("storeDB") db: Db) { this.orders = db.collection("orders"); } diff --git a/packages/server/src/adapters/product.repo.ts b/packages/server/src/adapters/product.repo.ts index b4d02b2..9225974 100644 --- a/packages/server/src/adapters/product.repo.ts +++ b/packages/server/src/adapters/product.repo.ts @@ -1,6 +1,6 @@ import { Collection, Db, ObjectId, WithId } from "mongodb"; import { Product, ProductTemplate } from "../types"; -import {Injectable} from "@nestjs/common"; +import {Inject, Injectable} from "@nestjs/common"; const docToProduct = ({_id, ...rest}: WithId) => Product.parse({id: _id.toString(), ...rest}); @@ -8,7 +8,7 @@ const docToProduct = ({_id, ...rest}: WithId) => Product.parse( export class MongoDBProductRepository { private products: Collection; - constructor(db: Db) { + constructor(@Inject("storeDB") db: Db) { this.products = db.collection("products"); } diff --git a/packages/server/src/app.module.ts b/packages/server/src/app.module.ioc.ts similarity index 91% rename from packages/server/src/app.module.ts rename to packages/server/src/app.module.ioc.ts index 91cc5e9..67890e6 100644 --- a/packages/server/src/app.module.ts +++ b/packages/server/src/app.module.ioc.ts @@ -6,10 +6,10 @@ import {CART_REPO, ORDER_REPO, PRODUCT_REPO} from "./adapters"; import {MemoryCartRepository} from "./adapters/cart.repo"; @Module({}) -export class AppModule { +export class AppModuleInversionOfControl { static register(productRepo: ProductRepository, orderRepo: OrderRepository): DynamicModule { return { - module: AppModule, + module: AppModuleInversionOfControl, providers: [ { provide: PRODUCT_REPO, diff --git a/packages/server/src/app.module.overrides.ts b/packages/server/src/app.module.overrides.ts new file mode 100644 index 0000000..2c5df8f --- /dev/null +++ b/packages/server/src/app.module.overrides.ts @@ -0,0 +1,11 @@ +import { Module} from "@nestjs/common"; +import {CartController, CheckoutController, OrderController, ProductController} from "./controllers"; +import {MongoDBModule} from "./adapters/mongodb.module"; + +@Module({ + imports: [MongoDBModule.forRoot(`mongodb://root:password@127.0.0.1`)], + controllers: [CartController, ProductController, OrderController, CheckoutController] +}) +export class AppModuleOverrides { + +} \ No newline at end of file diff --git a/packages/server/src/app.module.register.ts b/packages/server/src/app.module.register.ts new file mode 100644 index 0000000..df3cf24 --- /dev/null +++ b/packages/server/src/app.module.register.ts @@ -0,0 +1,14 @@ +import {DynamicModule, Module} from "@nestjs/common"; +import {CartController, CheckoutController, OrderController, ProductController} from "./controllers"; + + +@Module({}) +export class AppModuleWithRegister { + static register(adapters: DynamicModule) { + return { + imports: [adapters], + controllers: [CartController, ProductController, OrderController, CheckoutController], + module: AppModuleWithRegister + } + } +} \ No newline at end of file diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 68e0720..c9f39b8 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -2,9 +2,13 @@ import { MongoClient } from "mongodb"; import { MongoDBOrderRepository } from "./adapters/order.repo"; import { MongoDBProductRepository } from "./adapters/product.repo"; import {NestFactory} from "@nestjs/core"; -import {AppModule} from "./app.module"; +import {AppModuleInversionOfControl} from "./app.module.ioc"; +import {AppModuleOverrides} from "./app.module.overrides"; +import {AppModuleWithRegister} from "./app.module.register"; +import {MongoDBModule} from "./adapters/mongodb.module"; -async function startServer() { +// @ts-ignore +async function startServerIoC() { const mongo = await new MongoClient( `mongodb://root:password@127.0.0.1?retryWrites=true&writeConcern=majority` ).connect(); @@ -13,11 +17,26 @@ async function startServer() { const productRepo = new MongoDBProductRepository(db); const orderRepo = new MongoDBOrderRepository(db); - const app = await NestFactory.create(AppModule.register(productRepo, orderRepo)) + const app = await NestFactory.create(AppModuleInversionOfControl.register(productRepo, orderRepo)) app.enableCors({origin: "*"}); await app.listen(8080); } -void startServer(); +// @ts-ignore +async function startServerOverrides() { + const app = await NestFactory.create(AppModuleOverrides) + app.enableCors({origin: "*"}); + await app.listen(8080); +} + +async function startServerRegister() { + const app = await NestFactory.create(AppModuleWithRegister.register( + MongoDBModule.forRoot(`mongodb://root:password@127.0.0.1`) + )); + app.enableCors({origin: "*"}); + await app.listen(8080); +} + +void startServerRegister(); diff --git a/packages/server/src/server.testkit.ts b/packages/server/src/server.testkit.ts index 6ec34a0..8301106 100644 --- a/packages/server/src/server.testkit.ts +++ b/packages/server/src/server.testkit.ts @@ -1,12 +1,18 @@ import {ProductTemplate} from "./types"; import {Test} from "@nestjs/testing"; import {InMemoryOrderRepository, InMemoryProductRepository} from "./adapters/fake"; -import {AppModule} from "./app.module"; -export async function createTestingModule(products: ProductTemplate[] = []) { +import {AppModuleInversionOfControl} from "./app.module.ioc"; +import {AppModuleOverrides} from "./app.module.overrides"; +import {ORDER_REPO, PRODUCT_REPO} from "./adapters"; +import {MongoDBModule} from "./adapters/mongodb.module"; +import {Module} from "@nestjs/common"; +import {AppModuleWithRegister} from "./app.module.register"; +import {MemoryModule} from "./adapters/memory.module"; +export async function createTestingModuleWithIoC(products: ProductTemplate[] = []) { const productRepo = new InMemoryProductRepository(products); const orderRepo = new InMemoryOrderRepository(); const testingModule = await Test.createTestingModule({ - imports: [AppModule.register(productRepo, orderRepo)], + imports: [AppModuleInversionOfControl.register(productRepo, orderRepo)], }) .compile(); @@ -14,4 +20,49 @@ export async function createTestingModule(products: ProductTemplate[] = []) { nest.enableCors({origin: "*"}); await nest.init(); return {nest, orderRepo, productRepo}; -} \ No newline at end of file +} + +export async function createTestingModuleWithOverrides(products: ProductTemplate[] = []) { + const productRepo = new InMemoryProductRepository(products); + const orderRepo = new InMemoryOrderRepository(); + const testingModule = await Test.createTestingModule({ + imports: [AppModuleOverrides], + }) + .overrideModule(MongoDBModule).useModule(NopModule) // this doesn't actually do anything, MongoDB needs to be available for connection even though we don't use it + .overrideProvider(PRODUCT_REPO).useValue(productRepo) + .overrideProvider(ORDER_REPO).useValue(orderRepo) + .compile(); + + const nest = testingModule.createNestApplication(); + nest.enableCors({origin: "*"}); + await nest.init(); + return {nest, orderRepo, productRepo}; +} + +export async function createTestingModuleWithRegister(products: ProductTemplate[] = []) { + + const testingModule = await Test.createTestingModule({ + imports: [AppModuleWithRegister.register(MemoryModule.forTests(products))], + }) + .compile(); + + const productRepo: InMemoryProductRepository = testingModule.get(PRODUCT_REPO); + const orderRepo: InMemoryOrderRepository = testingModule.get(ORDER_REPO); + + const nest = testingModule.createNestApplication(); + nest.enableCors({origin: "*"}); + await nest.init(); + return {nest, orderRepo, productRepo}; +} + +// export const createTestingModule = createTestingModuleWithOverrides; +// export const createTestingModule = createTestingModuleWithIoC; +export const createTestingModule = createTestingModuleWithRegister; + +@Module({ + providers: [{ + provide: "storeDB", + useValue: null + }], +}) +class NopModule{} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 903f513..6be5c66 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1964,7 +1964,7 @@ __metadata: fastify-type-provider-zod: ^1.1.9 jest: ^28.1.3 mongodb: ^6.1.0 - nanoid: ^4.0.2 + nanoid: ^3.3.7 nodemon: ^3.0.1 reflect-metadata: ^0.2.2 rxjs: ^7.8.1 @@ -6611,6 +6611,15 @@ __metadata: languageName: node linkType: hard +"nanoid@npm:^3.3.7": + version: 3.3.7 + resolution: "nanoid@npm:3.3.7" + bin: + nanoid: bin/nanoid.cjs + checksum: d36c427e530713e4ac6567d488b489a36582ef89da1d6d4e3b87eded11eb10d7042a877958c6f104929809b2ab0bafa17652b076cdf84324aa75b30b722204f2 + languageName: node + linkType: hard + "nanoid@npm:^4.0.2": version: 4.0.2 resolution: "nanoid@npm:4.0.2"