Skip to content

Commit

Permalink
chore: refactor structure for repository and service pattern properly
Browse files Browse the repository at this point in the history
  • Loading branch information
brunotot committed May 12, 2024
1 parent 18cab27 commit 47a5b3b
Show file tree
Hide file tree
Showing 21 changed files with 194 additions and 182 deletions.
4 changes: 2 additions & 2 deletions packages/backend/src/config/singletons/ServiceRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ export class ServiceRegistry {

public inject<T>(nameOrContext: string | DecoratorContext): T {
if (typeof nameOrContext === "string") {
return this.container[nameOrContext] as T;
return this.container[nameOrContext.toLowerCase()] as T;
}
const containerName = InjectorMetadataManager.getBy(nameOrContext).value.name;
return this.container[containerName] as T;
return this.container[containerName.toLowerCase()] as T;
}

public iocStartup() {
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/decorators/@Autowired.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ServiceRegistry, InjectorMetadataManager } from "@org/backend/config";
export function Autowired<This, Value>() {
return createFieldDecorator<This, Value>(({ meta }) => {
const context = meta.context;
const fieldName = String(context.name);
const fieldName = String(context.name).toLowerCase();
InjectorMetadataManager.getBy(context).addDependency(fieldName);
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return function (_value: Value) {
Expand Down
19 changes: 5 additions & 14 deletions packages/backend/src/decorators/@Injectable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,15 @@ import type { TODO } from "@org/shared";
import { createClassDecorator, type ClassDecoratorSupplier } from "@org/backend/decorators";
import { ServiceRegistry, InjectorMetadataManager } from "@org/backend/config";

export function Injectable<This extends new () => TODO>(supplier?: ClassDecoratorSupplier<This>) {
export function Injectable<This extends new () => TODO>(
componentName: string,
supplier?: ClassDecoratorSupplier<This>,
) {
return createClassDecorator<This>(data => {
const { clazz: constructor, meta } = data;
const context = meta.context;
const constructorName: string = constructor.name;
const targetName = normalizeTargetName(constructorName);
InjectorMetadataManager.getBy(context).setName(targetName);
InjectorMetadataManager.getBy(context).setName(componentName.toLowerCase());
ServiceRegistry.getInstance().injectionClasses.push(constructor);
supplier?.(data);
});
}

function normalizeTargetName(targetName: string) {
const commonSuffix = "Impl";
const targetNameLength = targetName.length;
const targetNameSanitized = targetName.endsWith(commonSuffix)
? targetName.slice(0, targetNameLength - commonSuffix.length)
: targetName;
const uncapitalize = (str: string) => str.charAt(0).toLowerCase() + str.slice(1);
return uncapitalize(targetNameSanitized);
}
14 changes: 0 additions & 14 deletions packages/backend/src/decorators/@Repository.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/backend/src/decorators/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* @org/backend/decorators */
export * from "@org/backend/decorators/@Autowired";
export * from "@org/backend/decorators/@Injectable";
export * from "@org/backend/decorators/@Repository";
export * from "@org/backend/decorators/@Transactional";
export * from "@org/backend/decorators/@Contract";
export * from "@org/backend/decorators/setup";
24 changes: 24 additions & 0 deletions packages/backend/src/infrastructure/components/Database.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Environment } from "@org/backend/config";
import { Injectable } from "@org/backend/decorators";
import { type Db } from "mongodb";
import { type AnyZodObject, type z } from "zod";
import app from "@org/backend/worker";

@Injectable("database")
export class Database {
#client: Db;

get client() {
if (this.#client) return this.#client;
this.#client = app.mongoClient.db(Environment.getInstance().vars.DB_DATABASE);
return this.#client;
}

collection<T extends AnyZodObject>(zodSchema: T) {
const documentName = zodSchema.description;
if (!documentName) throw new Error("No document name provided.");
const lowerCaseName = documentName.toLowerCase();
const name = lowerCaseName.endsWith("s") ? lowerCaseName : `${lowerCaseName}s`;
return this.client.collection<z.infer<T>>(name);
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import bcrypt from "bcrypt";
import { JwtManager, type TokenData } from "@org/backend/config";
import { type UserRepository } from "@org/backend/infrastructure/repository/interface/UserRepository";
import { type UserRepository } from "@org/backend/infrastructure/repository/UserRepository";
import { withJwt } from "@org/backend/infrastructure/middleware/locals/withJwt";
import { withValidatedBody } from "@org/backend/infrastructure/middleware/locals/withValidatedBody";
import { Autowired, Contract, Injectable } from "@org/backend/decorators";
import type { RouteInput, RouteOutput } from "@org/backend/types";
import { LoginForm, ErrorResponse } from "@org/shared";

@Injectable()
@Injectable("authController")
export class AuthController {
@Autowired() userRepository: UserRepository;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Autowired, Contract, Injectable } from "@org/backend/decorators";
import { withPaginableParams } from "@org/backend/infrastructure/middleware/locals/withPaginableParams";
import { type UserService } from "@org/backend/infrastructure/service/UserService";

@Injectable()
@Injectable("userController")
export class UserController {
@Autowired() userService: UserService;

Expand Down
15 changes: 10 additions & 5 deletions packages/backend/src/infrastructure/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,18 @@ export * from "./middleware/locals/withPaginableParams";
export * from "./middleware/globals/index";

/* @org/backend/infrastructure/repository */
export * from "./repository/interface/PaginableRepository";
export * from "./repository/MongoRepository";
export * from "./repository/interface/UserRepository";
export * from "./repository/interface/ErrorLogRepository";
export * from "./repository/PaginableRepository";
export * from "./repository/UserRepository";
export * from "./repository/ErrorLogRepository";
export * from "./repository/impl/UserRepositoryImpl";
export * from "./repository/impl/ErrorLogRepositoryImpl";

/* @org/backend/infrastructure/service */
export * from "./service/UserService";
export * from "./service/impl/UserServiceImpl";
export * from "./service/impl/UserServiceImpl";

/* @org/backend/infrastructure/utils */
export * from "./utils/PaginationUtils";

/* @org/backend/infrastructure/components */
export * from "./components/Database";
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @packageDocumentation Middleware which serves static and public files from assets directory..
*/

import { RouteMiddleware } from "@org/backend/types";
import { type RouteMiddleware } from "@org/backend/types";
import type { RequestHandler } from "express";
import express from "express";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { type TODO, ErrorResponse } from "@org/shared";
import type { RequestHandler } from "express";
import type { AnyZodObject, ZodErrorMap, ZodIssue } from "zod";
import { getErrorMap } from "zod";

import { type ErrorLogRepository } from "@org/backend/infrastructure/repository/interface/ErrorLogRepository";
import { type ErrorLogRepository } from "@org/backend/infrastructure/repository/ErrorLogRepository";
import { ServiceRegistry } from "@org/backend/config";

export function withValidatedBody(schema: AnyZodObject): RequestHandler {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { type ErrorLog } from "@org/shared";
import { type PaginableRepository } from "@org/backend/infrastructure/repository/PaginableRepository";

export interface ErrorLogRepository extends PaginableRepository<ErrorLog> {
insertOne: (user: Omit<ErrorLog, "_id">) => Promise<ErrorLog>;
}
116 changes: 0 additions & 116 deletions packages/backend/src/infrastructure/repository/MongoRepository.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type User } from "@org/shared";
import { type PaginableRepository } from "@org/backend/infrastructure/repository/interface/PaginableRepository";
import { type PaginableRepository } from "@org/backend/infrastructure/repository/PaginableRepository";

export interface UserRepository extends PaginableRepository<User> {
findOneByUsername: (username: string) => Promise<User | null>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { Repository /*, Transactional*/ } from "@org/backend/decorators";
import { ObjectId, ErrorLog } from "@org/shared";
import { Autowired, Injectable /*, Transactional*/ } from "@org/backend/decorators";
import { ObjectId, ErrorLog, type PaginationResult } from "@org/shared";
import { type ErrorLogRepository } from "@org/backend/infrastructure/repository/ErrorLogRepository";
import { type Database } from "@org/backend/infrastructure/components/Database";
import { type MongoPaginationOptions } from "@org/backend/types";
import * as PaginationUtils from "@org/backend/infrastructure/utils/PaginationUtils";

import { MongoRepository } from "@org/backend/infrastructure/repository/MongoRepository";
import { type ErrorLogRepository } from "@org/backend/infrastructure/repository/interface/ErrorLogRepository";
@Injectable("errorLogRepository")
export class ErrorLogRepositoryImpl implements ErrorLogRepository {
@Autowired() private database: Database;

private get collection() {
return this.database.collection(ErrorLog);
}

search(options?: MongoPaginationOptions): Promise<PaginationResult<ErrorLog>> {
return PaginationUtils.paginate(this.collection, options);
}

@Repository(ErrorLog)
export class ErrorLogRepositoryImpl
extends MongoRepository<ErrorLog>
implements ErrorLogRepository
{
//@Transactional()
async insertOne(user: Omit<ErrorLog, "_id">): Promise<ErrorLog> {
const candidate = { ...user, _id: new ObjectId() };
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import { Repository } from "@org/backend/decorators";
import { User, ObjectId } from "@org/shared";
import { Autowired, Injectable } from "@org/backend/decorators";
import { User, ObjectId, type PaginationResult } from "@org/shared";
import * as PaginationUtils from "@org/backend/infrastructure/utils/PaginationUtils";
import { type UserRepository } from "@org/backend/infrastructure/repository/UserRepository";
import { type Database } from "@org/backend/infrastructure/components/Database";
import { type MongoPaginationOptions } from "@org/backend/types";

import { MongoRepository } from "@org/backend/infrastructure/repository/MongoRepository";
import { type UserRepository } from "@org/backend/infrastructure/repository/interface/UserRepository";
@Injectable("userRepository")
export class UserRepositoryImpl implements UserRepository {
@Autowired() private database: Database;

private get collection() {
return this.database.collection(User);
}

search(options?: MongoPaginationOptions): Promise<PaginationResult<User>> {
return PaginationUtils.paginate(this.collection, options);
}

@Repository(User)
export class UserRepositoryImpl extends MongoRepository<User> implements UserRepository {
async findOneByUsername(username: string): Promise<User | null> {
return await this.collection.findOne({ username });
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import type { TODO } from "@org/shared";
import type { PaginationResult } from "@org/shared";
import { Autowired, Injectable } from "@org/backend/decorators";
import { type MongoPaginationOptions } from "@org/backend/types";
import { type UserRepository } from "@org/backend/infrastructure/repository/interface/UserRepository";
import { type UserRepository } from "@org/backend/infrastructure/repository/UserRepository";
import { type UserService } from "@org/backend/infrastructure/service/UserService";
import { type User } from "@org/shared";

@Injectable()
@Injectable("userService")
export class UserServiceImpl implements UserService {
@Autowired() userRepository: UserRepository;

Expand Down
Loading

0 comments on commit 47a5b3b

Please sign in to comment.