Exploring Typescript and Clean Architecture with an In-Memory Database/Repository

Currently, I am integrating clean architecture in my latest project and facing challenges with repositories, data sources, and terminology.

My aim is to test my useCases using an in-memory repository as I am only concerned about the business logic at this point. However, I find it difficult to understand the terminology used and would appreciate some clarification on this matter.

To start off, I have defined a base DataSource as follows:

export interface DataSource<T> {    
    create(request: any): Promise<T>

    // other methods omitted for simplicity
}

Further, I have outlined the interface for Patient like so:

export interface PatientRepository {
    createPatient(patient: Patient): Promise<void>

    // other methods omitted for simplicity
}

For production purposes, I plan to utilize Sequelize, whereas for unit testing, I will employ a local array of entities.

In the event where I need to implement the PatientRepository, how should I proceed?

Option 1

I could develop a PatientSequelizeRepository that adheres to the methods specified in my contract and extends an abstract

SequelizeRepository</code which implements the <code>DataSource
contract. Additionally, I could also establish a PatientInMemoryRepository implementing the same methods but extending an abstract
InMemoryRepository</code which fulfills the <code>DataSource
contract. Subsequently, I would import the PatientInMemoryRepository within my use-case, and include the PatientSequelizeRepository in the app's composition.

Option 2

Alternatively, I may create a single implementation of the PatientRepository and pass a data-source parameter in the constructor since the methods for the PatientRepository remain consistent. I could introduce a generic InMemoryDataSource and SequelizeDataSource, both abiding by the DataSource contract. By default, I would construct the repository using the Sequelize implementation while providing flexibility to switch to alternative data sources if required.

export class PatientRepositoryImpl implements PatientRepository {
    constructor(dataSource: DataSource<Patient>) { }
    
    async createPatient(patient: Patient) {
       return this.dataSource.create(patient)
    }
}

export const patientRepository = new PatientRepositoryImpl(new SequelizeDataSource())

The naming conventions here pose a dilemma for me. While inserting a SequelizeDataSource into the constructor seems logical, should I create a PatientSequelizeDataSource, assign it to the constructor, and repeat the process for PatientInMemoryDataSource? Is there an optimal course of action? Could there perhaps be an unexplored third option I have overlooked?

Answer №1

One of the main considerations when it comes to repositories in Clean Architecture is whether the Dependency Rule is being violated or not.

If your Repository is situated in the "interface adapters" layer and your DataSource is in the "frameworks" layer, it is important that your Repository does not depend on any specific implementation of a DataSource.

In this context, Option 2 would align with the Dependency Rule if "by default I am constructing the repository with Sequelize implementation" means that you are injecting the Sequelize implementation into the Repository constructor within the "main" component of your application, rather than creating the Sequelize instance in the default constructor of the Repository.

For a more thorough exploration of how to correctly implement repositories in Clean Architecture, you can watch this video.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Exporting several functions within a TypeScript package is advantageous for allowing greater flexibility

Currently, I am in the process of developing an npm package using Typescript that includes a variety of functions. Right now, all the functions are being imported into a file called index.ts and then re-exported immediately: import { functionA, functionB ...

I've added a check, so why is TypeScript still complaining about the possibility of my property being undefined?

const handleLinkClick = (index: number) => () => { const hasUrl = !!searchItems[index]?.url; if (hasUrl) { navigateToLink(searchItems[index]?.url); } else { setItemSelected(index); } }; However, the issue I encountered is: (property) ...

"Can you share a method to extract the value from a TextField component in a React hook-based Material-

Currently, I am using Material-UI within a React project and have a component set up like this: const UserDetail = (props: ListDetailProps) => { const oldpassword = useRef<TextFieldProps>(null); const newpassword = useRef<TextFieldProps ...

The reCAPTCHA feature in Next.js form is returning an undefined window error, possibly due to an issue with

Trying to incorporate reCAPTCHA using react-hook-form along with react-hook-recaptcha is posing some challenges as an error related to 'window' being undefined keeps popping up: ReferenceError: window is not defined > 33 | const { recaptchaL ...

A comprehensive guide to using Reactive Forms in Angular

I need help understanding how FormGroup, FormControl, FormArray work in Angular. The error message I'm encountering is: Type '{ question: FormControl; multi: true; choices: FormArray; }' is not assignable to type 'AbstractControl' ...

Oops! There seems to be a hiccup: Unable to locate the control with the specified path: 'emails -> 0 -> email'

I am attempting to design a form incorporating a structure like this: formGroup formControl formControl formArray formGroup formControl formControl However, upon clicking the button to add reactive fields and submitting the form ...

Ignore verification of unused parameters

In my typescript project compilation process, I make use of the noImplicitAny option to ensure that I specify the types for variables and arguments. However, there are instances where I have unused arguments. For instance: jQuery.ajaxTransport("+*", func ...

Using JavaScript to place a particular tag at a designated position

I have a string that looks like this: var txtstr='<p>Text 1</p><p>&nbsp;</p><p>Text &nbsp;2</p><p>&nbsp;</p><p>Text 3&nbsp;</p>'; I have an <img src=..../> tag and ...

What is the Angular2 equivalent of the AngularJS $routeChangeStart event?

During our time working with AngularJS, we utilized the $routeChangeStart/End event in the $rootScope to monitor changes in the route object. What is the equivalent method for monitoring route changes in Angular2? How can we achieve the same functionality ...

A Guide to Catching Targeted React Notifications in Sentry using Next.js

In my Next.js application, I have implemented Sentry for error tracking. While I have successfully set up Sentry to capture errors within my try/catch blocks, I am currently struggling with capturing specific errors and warnings at a global level in my sen ...

Refreshing the cache in SWR, but the user interface remains unchanged inexplicably - SWR hook in Next.js with TypeScript

I am currently working on a project that resembles Facebook, and I am facing an issue with the like button functionality. Whenever I press the like button, I expect to see the change immediately, but unfortunately, SWR only updates after a delay of 4-8 sec ...

"Create a separate function for the pipeable operator in RXJS for enhanced code

After working on some code, I came up with the following implementation this.form.valueChanges.pipe( take(1), map(val => // doSomething), exhaustMap(val => // someInner observable logic return of({someValue}) ) ).subscrib ...

Connecting an Angular application to a URL hosted on localhost

I am currently working on an Angular project where one of the links needs to redirect to a different website. During development, this link points to a localhost URL like localhost:4210. However, due to security reasons in Angular, using such URLs is cons ...

Is there a way for me to determine the value that has been assigned to a <li> key attribute in React using Jest and testing-library/react?

In my current project, I am using a combination of React with TypeScript and Jest along with Testing Library for testing purposes. I have a specific requirement to unit test some code where I need to ensure that the person.id is correctly set as the key at ...

The TypeScript package encountered an unexpected token export

I have integrated a module from a private git repository. Package.json: "my-module": "git+https://username:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="cebeb98eaca7baacbbada5abbae0a1bca9">[email protected]</a> ...

When using the .concat method on an array, props may display as unidentified

When I log the items array in my props, it contains items. However, when I try to add to the array using .concat, I encounter an error stating Cannot read property 'concat' of undefined export default (props) => { const { items } = props; ...

The Ngrx action fails to finish despite encountering an error during execution

An Issue with Action Completion Post-Error Within my application, I have implemented an action for deleting a user. Prior to deletion, the user is prompted on screen with a Dialog to input the administrator password. If the correct password is provided, t ...

What are the differences between Modules and Typings in Typescript?

I have been searching far and wide for information on the variances between modules and typings in TypeScript, but I'm still struggling to grasp the concept. As a newcomer to TypeScript, could someone please provide a concise explanation of these diff ...

What is the best way to ensure complex types are properly initialized and functioning when declaring data within a vue.js module?

Utilizing a TypeScript class that I created called Budget to initialize data for a module has been proving to be challenging. When I attempt something like this: currBudget: {} = { id: 20, name: 'Chris' }; everything functions as expected. How ...

Creating spec.ts files for components by hand: A guide

Currently, I am facing an issue where the automatic generation of spec.ts files has been disabled by the developers when they created the components. To address this, I manually created the spec.ts files by copying over an existing one into each component, ...