diff options
Diffstat (limited to '2025/02/19')
| -rw-r--r-- | 2025/02/19/Repository-pattern-in-Typescript/index.html | 16 |
1 files changed, 7 insertions, 9 deletions
diff --git a/2025/02/19/Repository-pattern-in-Typescript/index.html b/2025/02/19/Repository-pattern-in-Typescript/index.html index c0753a94..99250448 100644 --- a/2025/02/19/Repository-pattern-in-Typescript/index.html +++ b/2025/02/19/Repository-pattern-in-Typescript/index.html @@ -198,30 +198,28 @@ <p>抽象化数据访问层的主要作用是将应用的业务逻辑与对数据库的数据访问等实现细节进行解耦。DB 框架的更改不应该影响到应用程序的核心服务,并且它们应该对业务逻辑代码透明。</p> <p>业务服务应该只依赖于抽象,而不是实现,数据服务同理。</p> <hr> -<h1 id="Intro"><a href="#Intro" class="headerlink" title="Intro."></a>Intro.</h1><p>例如,此时有一个书籍存储的微服务,并且有一个“添加新书籍”的操作用例,在此用例中可以通过使用 <code>Book</code> 这个 <em>Repository</em> 来添加新书籍,而 <code>Book</code> 具体使用什么数据库,怎么存并不是业务需要关心的事情。</p> -<h2 id="具体实现方式"><a href="#具体实现方式" class="headerlink" title="具体实现方式"></a>具体实现方式</h2><p>假设有以下实体类型定义:</p> +<h1>Intro.</h1> +<p>例如,此时有一个书籍存储的微服务,并且有一个“添加新书籍”的操作用例,在此用例中可以通过使用 <code>Book</code> 这个 <em>Repository</em> 来添加新书籍,而 <code>Book</code> 具体使用什么数据库,怎么存并不是业务需要关心的事情。</p> +<h2 id="具体实现方式"><a class="header-anchor" href="#具体实现方式">¶</a>具体实现方式</h2> +<p>假设有以下实体类型定义:</p> <figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">Author</span> {</span><br><span class="line"> <span class="attr">firstName</span>: <span class="built_in">string</span>;</span><br><span class="line"> <span class="attr">lastName</span>: <span class="built_in">string</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">Genre</span> {</span><br><span class="line"> <span class="attr">name</span>: <span class="built_in">string</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">Book</span> {</span><br><span class="line"> <span class="attr">title</span>: <span class="built_in">string</span>;</span><br><span class="line"> <span class="attr">author</span>: <span class="title class_">Author</span>;</span><br><span class="line"> <span class="attr">genre</span>: <span class="title class_">Genre</span>;</span><br><span class="line"> <span class="attr">publishDate</span>: <span class="title class_">Date</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure> - -<h3 id="抽象化"><a href="#抽象化" class="headerlink" title="抽象化"></a>抽象化</h3><p>第一步是抽象化出一个通用的 <em>Repository</em> ,其中包含通用的操作:</p> +<h3 id="抽象化"><a class="header-anchor" href="#抽象化">¶</a>抽象化</h3> +<p>第一步是抽象化出一个通用的 <em>Repository</em> ,其中包含通用的操作:</p> <figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">IGenericRepository</span><T> {</span><br><span class="line"> <span class="keyword">abstract</span> <span class="title function_">getAll</span>(): <span class="title class_">Promise</span><T[]>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">abstract</span> <span class="title function_">get</span>(<span class="attr">id</span>: <span class="built_in">string</span>): <span class="title class_">Promise</span><T>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">abstract</span> <span class="title function_">create</span>(<span class="attr">item</span>: T): <span class="title class_">Promise</span><T>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">abstract</span> <span class="title function_">update</span>(<span class="attr">id</span>: <span class="built_in">string</span>, <span class="attr">item</span>: T);</span><br><span class="line">}</span><br></pre></td></tr></table></figure> - <ul> <li>这里具体有那些函数可以根据需要(业务)自己定义。</li> <li>类型参数 <code>T</code> 表示每个实体。</li> </ul> -<p>接着,定义一个数据服务,其中包含使用 <code>IGenericRepositoiry</code> 定义的具体实例对应的 _Repository_:</p> +<p>接着,定义一个数据服务,其中包含使用 <code>IGenericRepositoiry</code> 定义的具体实例对应的 <em>Repository</em>:</p> <figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { <span class="title class_">Author</span>, <span class="title class_">Book</span>, <span class="title class_">Genre</span> } <span class="keyword">from</span> <span class="string">'../entities'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">IGenericRepository</span> } <span class="keyword">from</span> <span class="string">'./generic-repository.abstract'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">IDataServices</span> {</span><br><span class="line"> <span class="keyword">abstract</span> <span class="attr">authors</span>: <span class="title class_">IGenericRepository</span><<span class="title class_">Author</span>>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">abstract</span> <span class="attr">books</span>: <span class="title class_">IGenericRepository</span><<span class="title class_">Book</span>>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">abstract</span> <span class="attr">genres</span>: <span class="title class_">IGenericRepository</span><<span class="title class_">Genre</span>>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure> - <ul> <li>这里有三个 <em>Repository</em> 分别对应不同的实体。</li> <li><code>IGenericRepository</code> 中定义的函数是每个 <em>Repository</em> 公开的通用存储函数。</li> </ul> <p>以上这些就是对业务中的实体的 <em>Repository</em> 抽象,这样就隔离开了业务和存储逻辑,例如使用 MongoDB,可以实现一个 <code>MongoGenericRepository</code>:</p> <figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { <span class="title class_">Model</span> } <span class="keyword">from</span> <span class="string">'mongoose'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">IGenericRepository</span> } <span class="keyword">from</span> <span class="string">'../../../core'</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">MongoGenericRepository</span><T> <span class="keyword">implements</span> <span class="title class_">IGenericRepository</span><T> {</span><br><span class="line"> <span class="keyword">private</span> <span class="attr">_repository</span>: <span class="title class_">Model</span><T>;</span><br><span class="line"> <span class="keyword">private</span> <span class="attr">_populateOnFind</span>: <span class="built_in">string</span>[];</span><br><span class="line"></span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params"><span class="attr">repository</span>: <span class="title class_">Model</span><T>, <span class="attr">populateOnFind</span>: <span class="built_in">string</span>[] = []</span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">_repository</span> = repository;</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">_populateOnFind</span> = populateOnFind;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">getAll</span>(): <span class="title class_">Promise</span><T[]> {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_repository</span>.<span class="title function_">find</span>().<span class="title function_">populate</span>(<span class="variable language_">this</span>.<span class="property">_populateOnFind</span>).<span class="title function_">exec</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">get</span>(<span class="attr">id</span>: <span class="built_in">any</span>): <span class="title class_">Promise</span><T> {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_repository</span>.<span class="title function_">findById</span>(id).<span class="title function_">populate</span>(<span class="variable language_">this</span>.<span class="property">_populateOnFind</span>).<span class="title function_">exec</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">create</span>(<span class="attr">item</span>: T): <span class="title class_">Promise</span><T> {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_repository</span>.<span class="title function_">create</span>(item);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="title function_">update</span>(<span class="params"><span class="attr">id</span>: <span class="built_in">string</span>, <span class="attr">item</span>: T</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_repository</span>.<span class="title function_">findByIdAndUpdate</span>(id, item);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure> - <p>然后实现一个 <code>MongoDataServices</code>:</p> <figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> { <span class="title class_">Injectable</span>, <span class="title class_">OnApplicationBootstrap</span> } <span class="keyword">from</span> <span class="string">'@nestjs/common'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">InjectModel</span> } <span class="keyword">from</span> <span class="string">'@nestjs/mongoose'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">Model</span> } <span class="keyword">from</span> <span class="string">'mongoose'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">IDataServices</span> } <span class="keyword">from</span> <span class="string">'../../../core'</span>;</span><br><span class="line"><span class="keyword">import</span> { <span class="title class_">MongoGenericRepository</span> } <span class="keyword">from</span> <span class="string">'./mongo-generic-repository'</span>;</span><br><span class="line"><span class="keyword">import</span> {</span><br><span class="line"> <span class="title class_">Author</span>,</span><br><span class="line"> <span class="title class_">AuthorDocument</span>,</span><br><span class="line"> <span class="title class_">Book</span>,</span><br><span class="line"> <span class="title class_">BookDocument</span>,</span><br><span class="line"> <span class="title class_">Genre</span>,</span><br><span class="line"> <span class="title class_">GenreDocument</span>,</span><br><span class="line">} <span class="keyword">from</span> <span class="string">'./model'</span>;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Injectable</span>()</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">MongoDataServices</span></span><br><span class="line"> <span class="keyword">implements</span> <span class="title class_">IDataServices</span>, <span class="title class_">OnApplicationBootstrap</span></span><br><span class="line">{</span><br><span class="line"> <span class="attr">authors</span>: <span class="title class_">MongoGenericRepository</span><<span class="title class_">Author</span>>;</span><br><span class="line"> <span class="attr">books</span>: <span class="title class_">MongoGenericRepository</span><<span class="title class_">Book</span>>;</span><br><span class="line"> <span class="attr">genres</span>: <span class="title class_">MongoGenericRepository</span><<span class="title class_">Genre</span>>;</span><br><span class="line"></span><br><span class="line"> <span class="title function_">constructor</span>(<span class="params"></span></span><br><span class="line"><span class="params"> <span class="meta">@InjectModel</span>(Author.name)</span></span><br><span class="line"><span class="params"> <span class="keyword">private</span> <span class="title class_">AuthorRepository</span>: <span class="title class_">Model</span><<span class="title class_">AuthorDocument</span>>,</span></span><br><span class="line"><span class="params"> <span class="meta">@InjectModel</span>(Book.name)</span></span><br><span class="line"><span class="params"> <span class="keyword">private</span> <span class="title class_">BookRepository</span>: <span class="title class_">Model</span><<span class="title class_">BookDocument</span>>,</span></span><br><span class="line"><span class="params"> <span class="meta">@InjectModel</span>(Genre.name)</span></span><br><span class="line"><span class="params"> <span class="keyword">private</span> <span class="title class_">GenreRepository</span>: <span class="title class_">Model</span><<span class="title class_">GenreDocument</span>>,</span></span><br><span class="line"><span class="params"> </span>) {}</span><br><span class="line"></span><br><span class="line"> <span class="title function_">onApplicationBootstrap</span>(<span class="params"></span>) {</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">authors</span> = <span class="keyword">new</span> <span class="title class_">MongoGenericRepository</span><<span class="title class_">Author</span>>(<span class="variable language_">this</span>.<span class="property">AuthorRepository</span>);</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">books</span> = <span class="keyword">new</span> <span class="title class_">MongoGenericRepository</span><<span class="title class_">Book</span>>(<span class="variable language_">this</span>.<span class="property">BookRepository</span>, [</span><br><span class="line"> <span class="string">'author'</span>,</span><br><span class="line"> <span class="string">'genre'</span>,</span><br><span class="line"> ]);</span><br><span class="line"> <span class="variable language_">this</span>.<span class="property">genres</span> = <span class="keyword">new</span> <span class="title class_">MongoGenericRepository</span><<span class="title class_">Genre</span>>(<span class="variable language_">this</span>.<span class="property">GenreRepository</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure> - <hr> <p>Sunday, March 30, 2025 7:58 PM:</p> <p>感觉以上全错,不应该过度抽象 Repository 的,就让它分散在各个模块中,还可以参考 <a target="_blank" rel="noopener" href="https://github.com/Papooch/nestjs-cls">https://github.com/Papooch/nestjs-cls</a> 实现不会抽象泄漏的事务性 Repository 方法。</p> |
