1

I have a custom repository for each entity/module (I'm working with NestJS). I know that this is a lot of repeated code and I may refactor it in order to use a generic repository later, but currently I'm focused on making a simple working MVP.

My current doubt is: I have some entity specific scenarios to get data. eg. get all articles associated to an user.

Should I implement a repository method like:

// In the repository
async getByUserId(userId: string): Promise<Article[]> {
    ...
}

Or should I implement this kind of logic in the service layer, using the getAll and filtering it within the service, eg:

// In the service
async getByUserId(userId: string) Promise<Article[]> {
    const articles = await this.articleRepository.getAll();
    const filteredArticles = articles.filter(article => article.userId == userId);
    return filteredArticles;
}

There are multiple cases where this kind of 'domain' specific logic happens and I'd like to define a pattern that follows best practices and follow it throughout the codebase.


EDIT: After @Philip Kendall's answer, it is clear that leaving this kind of logic to the service is a bad idea, so my question has shifted: Should I create many specific gets, as described above, or should I pass options to a more general get, like the following:

export type GetArticleOptions = {
    id?: string;
    userId?: string;
};

async getAll(options?: GetArticleOptions): Promise<Article[]> {
    const opt = { where: { ...options } };
    return await this.articleRepository.find(opt);
}
2
  • 2
    In your second example, are you pulling every article into memory and then filtering? While I'm generally among the first to say "premature optimization", that seems like a bad idea. Commented Nov 15, 2023 at 14:50
  • @PhilipKendall, I thought so as well, but I don't really know if there's another way of moving the logic from the repository to the service without doing that. Your argument is in favor of creating multiple domain specific repository methods then? That way we would load only the necessary articles. Another option might be passing an options object to the get method in the repository... Commented Nov 15, 2023 at 15:04

2 Answers 2

1

Should I create many specific gets, as described above, or should I pass options to a more general get, like the following

The quoted question rephrased is "should I write more code or should I write less code?" and the answer depends on the number of options passed to the repository method since now the choice is between write more code that runs faster or write less code that runs slower. More code (specific gets) has low complexity the query being statical while with less code (all in one get) the query is dynamically built based on received options.

So if you want to do what I recommend then go write more code.

2

scenarios to get data. eg. get all articles associated to an user.

Dragging all articles into memory and then filtering by user is certainly one way to implement. It can work well, especially if you have an in-core hashmap or a datastructure ordered by user name.

But when N = num_articles is large, you may be unhappy with the memory complexity of that solution. Consider relying on the external storage of an RDBMS, perhaps sqlite or one of its competitors.

Then your entity can be a thin facade over an ORM or other database access layer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.