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

Where can I find the @types for a specific lodash package?

Seeking to utilize a specific function from lodash - assignin. I have successfully installed lodash.assignin and incorporated it into my project: import assignIn = require('lodash.assignin'); However, when compiling, an error occurs: "error TS2 ...

Utilizing Angular 2 alongside ngrx/store for seamless updates to specific properties within the state object without disrupting the entire structure

I am facing an issue where I need to update a property of a state object without creating a new object. Is there a way to add or update a single property without replacing the entire object? Below is the reducer code: const initialState = { all: [], ...

Executing multiple http post requests in Angular2 using a for loop

I've encountered an issue while attempting to upload multiple files with individual titles. The problem arises when sending requests to the server, as I'm trying to pass each file and its corresponding title one by one. I have an array called bin ...

TypeScript and Redux mapDispatchToProps are not in sync

Below is my React component written in TypeScript: import React from 'react'; import {connect, ConnectedProps} from 'react-redux'; import logo from './assets/logo.png'; // import { Counter } from './features/counter/Count ...

Utilizing a variable name as an object key in TypeScript

Can this be achieved? static readonly statusMapping: { [key in UploadStatus]: PopupMessageStatus } = { UploadStatus.COMPLETED : PopupMessageStatus.COMPLETED } UploadStatus is an enum with numeric values, where UploadStatus.COMPLETED = 0 p ...

Rendering a React/Material UI class based on the state variable in a conditional manner

I am currently working on building a basic navbar setup using React and Material UI. I have encountered an issue where React-Router-Dom does not seem to be functioning within this particular project, and implementing it would be excessive for the simple ta ...

Injectable error occurred while injecting one @Injectable() into another

I'm encountering an issue with Angular2 Dependency Injection. When attempting to inject one class into another, I am receiving the following error: Error Message: "Cannot resolve all parameters for 'ProductService'(undefined). Make sure tha ...

How to capture a screenshot of the current screen using Nativescript programmatically

After taking a screenshot in a NativeScript app, is there a way to display a popup asking if the user wants to save the picture? I attempted using the 'nativescript-screenshot' plugin, but it only copies elements within the application: nat ...

Unit testing the TypeScript function with Karma, which takes NgForm as a parameter

As I work on writing unit tests for a specific method, I encounter the following code: public addCred:boolean=true; public credName:any; public addMachineCredential(credentialForm: NgForm) { this.addCred = true; this.credName = credentialForm.val ...

cssclassName={ validatorState === RIGHT ? 'valid' : 'invalid' }

Is there a way to dynamically add different classes based on validation outcomes in React? My current implementation looks like this: className={ validatorState === RIGHT ? 'ok' : 'no' } However, I also need to handle cases where the ...

Error message in VueJS TypeScript: Implicit declaration of type 'props' as 'any'

Currently, I am working with vue 2.6 and typescript 3.8.3. The issue arises when I attempt to apply a validator to a prop. I am encountering error message TS7006: Parameter 'props' implicitly has an 'any' type. Below is the ...

When running on localhost, IE11 only shows a white screen while the other browsers function properly

I have recently completed a web-based project and successfully deployed it. The project is running on port 8080. Upon testing in Chrome, Safari, and Firefox, the project functions without any issues, and no errors are displayed in the console. However, wh ...

JavaScript has a feature called "functions" which allow the declaration of named blocks of

Currently, I am developing an Electron app in typescript. In my main.ts file, I have instantiated a custom CommunicationProvider class object. What I want is for this class to declare multiple methods (specified in an interface that it implements) but have ...

What is the best way to add a hyperlink to a cell in an Angular Grid column

I need help creating a link for a column cell in my angular grid with a dynamic job id, like /jobs/3/job-maintenance/general. In this case, 3 is the job id. I have element.jobId available. How can I achieve this? Here is the code for the existing column: ...

What are the steps to integrate TypeScript into JavaScript code?

How can I import a TypeScript class in a Node CommonJS JavaScript file? When using mongoose in my TypeScript code, I typically do the following: // user.model.ts export const UserModel = model<User>('User', schema); In my JavaScript code: ...

Loading data into the Nuxt store upon application launch

Currently, I'm working on an app using Nuxt where I preload some data at nuxtServerInit and store it successfully. However, as I have multiple projects with similar initial-preload requirements, I thought of creating a reusable module for this logic. ...

How to Retrieve an Array from a Promise Using Angular 4 and Typescript

I am encountering difficulties when trying to store data from a returned promise. To verify that the desired value has been returned, I log it in this manner: private fetchData() { this._movieFranchiseService.getHighestGrossingFilmFranchises() ...

Having trouble with errors when trying to implement react-router-v6 with typescript

Having trouble with my code and receiving the following error: "Argument of type 'HTMLElement | null' is not assignable to parameter of type 'Element | DocumentFragment'. Type 'null' is not assignable to type 'Element | ...

Perplexed by the persistent failure of this Jasmine test accompanied by a vexing "timer in queue" error

I'm attempting to test a function that uses RxJS to broadcast long press events to subscribers. Below is the implementation of the function: export function watchForLongPress(target: HTMLElement) { let timer: number; const notifier = new Subject& ...

When working with Angular 5, the question arises: how and where to handle type conversion between form field values (typically strings) and model properties (such

As a newcomer to Angular, I am struggling with converting types between form field values (which are always strings) and typed model properties. In the following component, my goal is to double a number inputted by the user. The result will be displayed i ...