Rules Hub
Coding Rules Library
Avoid specialized repository methods for filter combinations
Do not create specialized repository methods for specific filter combinations; rely on chainable (fluent) methods and a single terminal execution method.
Bad example
| 1 | class ArticleRepository extends BaseRepository { |
| 2 | // BAD: Creates a specific method just to apply one filter |
| 3 | // Duplicates the fetching and mapping logic found in landingPageTeasers() |
| 4 | public async getTeasersByTag(tagName: string): Promise<Teaser[]> { |
| 5 | return (await this.byTagName(tagName).asArray()) |
| 6 | .map(article => article.toTeaser()); |
| 7 | } |
| 8 |
|
| 9 | public async landingPageTeasers(): Promise<Teaser[]> { |
| 10 | return (await this.asArray()).map(article => article.toTeaser()); |
| 11 | } |
| 12 | } |
Explanation (EN)
This approach leads to method explosion (e.g., `getTeasersByCategory`, `getTeasersByTag`). It duplicates the terminal logic (fetching and mapping) in every specialized method, making the class harder to maintain.
Objašnjenje (HR)
Ovaj pristup dovodi do prevelikog broja metoda (npr. `getTeasersByCategory`, `getTeasersByTag`). Duplira logiku dohvaćanja i mapiranja u svakoj specifičnoj metodi, što otežava održavanje klase.
Good example
| 1 | class ArticleRepository extends BaseRepository { |
| 2 | // GOOD: Expose filters as chainable methods |
| 3 | public byTagName(tagName: string) { |
| 4 | this.addFilter('tagName', tagName); |
| 5 | return this; |
| 6 | } |
| 7 |
|
| 8 | // GOOD: Only one terminal method defines the execution and mapping |
| 9 | public async landingPageTeasers(): Promise<Teaser[]> { |
| 10 | // Respects whatever filters were applied via the chain |
| 11 | return (await this.asArray()).map(article => article.toTeaser()); |
| 12 | } |
| 13 | } |
| 14 |
|
| 15 | // Usage: await repo.byTagName('news').landingPageTeasers(); |
Explanation (EN)
By using a fluent interface, filters are composable. The consumer applies filters (`byTagName`) and then calls the reusable terminal method (`landingPageTeasers`), avoiding duplication of the mapping logic.
Objašnjenje (HR)
Korištenjem fluent sučelja, filteri postaju složivi. Potrošač primjenjuje filtere (`byTagName`) i zatim poziva ponovno iskoristivu terminalnu metodu (`landingPageTeasers`), izbjegavajući dupliranje logike mapiranja.
Notes (EN)
In a Repository pattern, separate 'criteria building' (chainable methods that return `this`) from 'execution' (methods that return data).
Bilješke (HR)
U Repository obrascu, odvojite 'izgradnju kriterija' (lančane metode koje vraćaju `this`) od 'izvršavanja' (metode koje vraćaju podatke).