docs: collect refreshed mongo-ops wiki site (API-correct overhaul, v0.1.5)
This commit is contained in:
@@ -74,7 +74,7 @@
|
||||
<div data-md-component="skip">
|
||||
|
||||
|
||||
<a href="#use-case-7-caching-for-highperformance-reads" class="md-skip">
|
||||
<a href="#use-case-7-caching-for-high-performance-reads" class="md-skip">
|
||||
Skip to content
|
||||
</a>
|
||||
|
||||
@@ -457,7 +457,7 @@
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
02 components
|
||||
Core Components
|
||||
|
||||
</span>
|
||||
|
||||
@@ -711,54 +711,45 @@
|
||||
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#1-whats-new" class="md-nav__link">
|
||||
<a href="#whats-new" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
1️⃣ What’s New?
|
||||
📦 What's New?
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#2-quick-start" class="md-nav__link">
|
||||
<a href="#example" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
2️⃣ Quick Start
|
||||
🚀 Example
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#3-using-the-repository" class="md-nav__link">
|
||||
<a href="#redis-backend" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
3️⃣ Using the Repository
|
||||
🔄 Redis Backend
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#4-redis-backend-optional" class="md-nav__link">
|
||||
<a href="#tips" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
4️⃣ Redis Backend (optional)
|
||||
💡 Tips
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#5-when-to-use-caching" class="md-nav__link">
|
||||
<a href="#related" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
5️⃣ When to Use Caching
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#6-related-docs" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
6️⃣ Related Docs
|
||||
Related
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -1053,104 +1044,139 @@
|
||||
|
||||
|
||||
|
||||
<h1 id="use-case-7-caching-for-highperformance-reads">Use Case 7: Caching for High‑Performance Reads</h1>
|
||||
<p><strong>Scenario:</strong> A read‑heavy API (e.g., product catalog) benefits from an in‑memory cache or Redis cache to reduce latency and DB load.</p>
|
||||
<h1 id="use-case-7-caching-for-high-performance-reads">Use Case 7: Caching for High-Performance Reads</h1>
|
||||
<p><strong>Scenario:</strong> A read-heavy API (product catalog) reduces DB load by caching documents by <code>_id</code> — in-memory locally, or shared via Redis.</p>
|
||||
<hr />
|
||||
<h2 id="1-whats-new">1️⃣ What’s New?</h2>
|
||||
<ul>
|
||||
<li><strong>Cache back‑ends</strong>: <code>InMemoryCacheBackend</code> (TTL + LRU) and <code>RedisCacheBackend</code> (JSON‑serialised values, pub/sub invalidation).</li>
|
||||
<li><strong>Cache configuration</strong> via <code>CacheConfig</code> (<code>enabled</code>, <code>backend</code>, <code>default_ttl</code>, …).</li>
|
||||
<li><strong><code>CachedBaseRepository</code></strong> extends <code>BaseRepository</code> and adds:</li>
|
||||
<li>Transparent ID‑based caching on <code>get_by_id</code>.</li>
|
||||
<li>Automatic cache population on <code>create</code>.</li>
|
||||
<li>Cache invalidation on <code>update</code>/<code>delete</code>.</li>
|
||||
<li>Utility methods <code>warm_cache(ids)</code> and <code>invalidate_cache(id)</code>.</li>
|
||||
</ul>
|
||||
<h2 id="whats-new">📦 What's New?</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Component</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>InMemoryCacheBackend</code></td>
|
||||
<td>TTL + LRU cache with a background cleanup task.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>RedisCacheBackend</code></td>
|
||||
<td>Distributed cache on <code>redis.asyncio</code> with pub/sub invalidation.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>CachedBaseRepository[T]</code></td>
|
||||
<td>Extends <code>BaseRepository</code> — cache-first <code>get_by_id</code>, cache on <code>create</code>, invalidate on <code>update</code>/<code>delete</code>, <code>warm_cache(ids)</code>, <code>invalidate_cache(id)</code>.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Backend lifecycle</td>
|
||||
<td>The <strong>same</strong> backend instance must be both passed to the repository AND registered via <code>ModelRegistry.set_cache_backend</code> so <code>initialize_cache()</code> starts its task.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="2-quick-start">2️⃣ Quick Start</h2>
|
||||
<div class="language-python highlight"><span class="filename">Python</span><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">mongo_ops</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
|
||||
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a> <span class="n">BaseDocument</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a> <span class="n">CachedBaseRepository</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a> <span class="n">MongoConnectionManager</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a> <span class="n">ModelRegistry</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a> <span class="n">CacheConfig</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a><span class="p">)</span>
|
||||
<a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a><span class="kn">from</span><span class="w"> </span><span class="nn">mongo_ops.cache</span><span class="w"> </span><span class="kn">import</span> <span class="n">InMemoryCacheBackend</span>
|
||||
<a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a><span class="kn">from</span><span class="w"> </span><span class="nn">bson</span><span class="w"> </span><span class="kn">import</span> <span class="n">ObjectId</span>
|
||||
<a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a>
|
||||
<a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a><span class="c1"># Define a model</span>
|
||||
<a id="__codelineno-0-12" name="__codelineno-0-12" href="#__codelineno-0-12"></a><span class="k">class</span><span class="w"> </span><span class="nc">Product</span><span class="p">(</span><span class="n">BaseDocument</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-13" name="__codelineno-0-13" href="#__codelineno-0-13"></a> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
||||
<a id="__codelineno-0-14" name="__codelineno-0-14" href="#__codelineno-0-14"></a> <span class="n">price</span><span class="p">:</span> <span class="nb">float</span>
|
||||
<a id="__codelineno-0-15" name="__codelineno-0-15" href="#__codelineno-0-15"></a>
|
||||
<a id="__codelineno-0-16" name="__codelineno-0-16" href="#__codelineno-0-16"></a><span class="c1"># Initialise cache backend (in‑memory example)</span>
|
||||
<a id="__codelineno-0-17" name="__codelineno-0-17" href="#__codelineno-0-17"></a><span class="n">cache</span> <span class="o">=</span> <span class="n">InMemoryCacheBackend</span><span class="p">(</span><span class="n">max_entries</span><span class="o">=</span><span class="mi">10_000</span><span class="p">,</span> <span class="n">default_ttl</span><span class="o">=</span><span class="mi">300</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-18" name="__codelineno-0-18" href="#__codelineno-0-18"></a><span class="c1"># Register the cache so the registry can initialise it later</span>
|
||||
<a id="__codelineno-0-19" name="__codelineno-0-19" href="#__codelineno-0-19"></a><span class="n">ModelRegistry</span><span class="o">.</span><span class="n">set_cache_backend</span><span class="p">(</span><span class="n">cache</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-20" name="__codelineno-0-20" href="#__codelineno-0-20"></a>
|
||||
<a id="__codelineno-0-21" name="__codelineno-0-21" href="#__codelineno-0-21"></a><span class="c1"># Repository with caching</span>
|
||||
<a id="__codelineno-0-22" name="__codelineno-0-22" href="#__codelineno-0-22"></a><span class="k">class</span><span class="w"> </span><span class="nc">ProductRepo</span><span class="p">(</span><span class="n">CachedBaseRepository</span><span class="p">[</span><span class="n">Product</span><span class="p">]):</span>
|
||||
<a id="__codelineno-0-23" name="__codelineno-0-23" href="#__codelineno-0-23"></a> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-24" name="__codelineno-0-24" href="#__codelineno-0-24"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span>
|
||||
<a id="__codelineno-0-25" name="__codelineno-0-25" href="#__codelineno-0-25"></a> <span class="n">collection_name</span><span class="o">=</span><span class="s2">"products"</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-26" name="__codelineno-0-26" href="#__codelineno-0-26"></a> <span class="n">model</span><span class="o">=</span><span class="n">Product</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-27" name="__codelineno-0-27" href="#__codelineno-0-27"></a> <span class="n">cache_backend</span><span class="o">=</span><span class="n">cache</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-28" name="__codelineno-0-28" href="#__codelineno-0-28"></a> <span class="n">config</span><span class="o">=</span><span class="n">CacheConfig</span><span class="p">(</span><span class="n">enabled</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">backend</span><span class="o">=</span><span class="s2">"memory"</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-29" name="__codelineno-0-29" href="#__codelineno-0-29"></a> <span class="p">)</span>
|
||||
<a id="__codelineno-0-30" name="__codelineno-0-30" href="#__codelineno-0-30"></a>
|
||||
<a id="__codelineno-0-31" name="__codelineno-0-31" href="#__codelineno-0-31"></a><span class="c1"># FastAPI lifespan – initialise DB and cache</span>
|
||||
<a id="__codelineno-0-32" name="__codelineno-0-32" href="#__codelineno-0-32"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">lifespan</span><span class="p">(</span><span class="n">app</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-33" name="__codelineno-0-33" href="#__codelineno-0-33"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">MongoConnectionManager</span><span class="o">.</span><span class="n">lifespan</span><span class="p">(</span>
|
||||
<a id="__codelineno-0-34" name="__codelineno-0-34" href="#__codelineno-0-34"></a> <span class="n">uri</span><span class="o">=</span><span class="s2">"mongodb://localhost:27017"</span><span class="p">,</span> <span class="n">db_name</span><span class="o">=</span><span class="s2">"shop"</span>
|
||||
<a id="__codelineno-0-35" name="__codelineno-0-35" href="#__codelineno-0-35"></a> <span class="p">):</span>
|
||||
<a id="__codelineno-0-36" name="__codelineno-0-36" href="#__codelineno-0-36"></a> <span class="k">await</span> <span class="n">ModelRegistry</span><span class="o">.</span><span class="n">initialize_all</span><span class="p">()</span>
|
||||
<a id="__codelineno-0-37" name="__codelineno-0-37" href="#__codelineno-0-37"></a> <span class="k">await</span> <span class="n">ModelRegistry</span><span class="o">.</span><span class="n">initialize_cache</span><span class="p">()</span> <span class="c1"># Starts background cleanup, etc.</span>
|
||||
<a id="__codelineno-0-38" name="__codelineno-0-38" href="#__codelineno-0-38"></a> <span class="k">yield</span>
|
||||
<h2 id="example">🚀 Example</h2>
|
||||
<div class="language-python highlight"><span class="filename">Python</span><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">contextlib</span><span class="w"> </span><span class="kn">import</span> <span class="n">asynccontextmanager</span>
|
||||
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a>
|
||||
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="kn">from</span><span class="w"> </span><span class="nn">fastapi</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastAPI</span><span class="p">,</span> <span class="n">HTTPException</span>
|
||||
<a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="kn">from</span><span class="w"> </span><span class="nn">mongo_ops</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseDocument</span><span class="p">,</span> <span class="n">ModelRegistry</span><span class="p">,</span> <span class="n">MongoConnectionManager</span>
|
||||
<a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a><span class="kn">from</span><span class="w"> </span><span class="nn">mongo_ops.cache</span><span class="w"> </span><span class="kn">import</span> <span class="n">CacheConfig</span><span class="p">,</span> <span class="n">CachedBaseRepository</span><span class="p">,</span> <span class="n">InMemoryCacheBackend</span>
|
||||
<a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a>
|
||||
<a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a>
|
||||
<a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a><span class="k">class</span><span class="w"> </span><span class="nc">Product</span><span class="p">(</span><span class="n">BaseDocument</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">""</span>
|
||||
<a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a> <span class="n">price</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">0.0</span>
|
||||
<a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a>
|
||||
<a id="__codelineno-0-12" name="__codelineno-0-12" href="#__codelineno-0-12"></a>
|
||||
<a id="__codelineno-0-13" name="__codelineno-0-13" href="#__codelineno-0-13"></a><span class="c1"># One shared backend — used by both the repository and the registry lifecycle.</span>
|
||||
<a id="__codelineno-0-14" name="__codelineno-0-14" href="#__codelineno-0-14"></a><span class="n">cache</span> <span class="o">=</span> <span class="n">InMemoryCacheBackend</span><span class="p">(</span><span class="n">max_entries</span><span class="o">=</span><span class="mi">10_000</span><span class="p">,</span> <span class="n">default_ttl</span><span class="o">=</span><span class="mi">300</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-15" name="__codelineno-0-15" href="#__codelineno-0-15"></a><span class="n">ModelRegistry</span><span class="o">.</span><span class="n">set_cache_backend</span><span class="p">(</span><span class="n">cache</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-16" name="__codelineno-0-16" href="#__codelineno-0-16"></a>
|
||||
<a id="__codelineno-0-17" name="__codelineno-0-17" href="#__codelineno-0-17"></a>
|
||||
<a id="__codelineno-0-18" name="__codelineno-0-18" href="#__codelineno-0-18"></a><span class="k">class</span><span class="w"> </span><span class="nc">ProductRepo</span><span class="p">(</span><span class="n">CachedBaseRepository</span><span class="p">[</span><span class="n">Product</span><span class="p">]):</span>
|
||||
<a id="__codelineno-0-19" name="__codelineno-0-19" href="#__codelineno-0-19"></a> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-20" name="__codelineno-0-20" href="#__codelineno-0-20"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span>
|
||||
<a id="__codelineno-0-21" name="__codelineno-0-21" href="#__codelineno-0-21"></a> <span class="n">collection_name</span><span class="o">=</span><span class="s2">"products"</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-22" name="__codelineno-0-22" href="#__codelineno-0-22"></a> <span class="n">model</span><span class="o">=</span><span class="n">Product</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-23" name="__codelineno-0-23" href="#__codelineno-0-23"></a> <span class="n">cache_backend</span><span class="o">=</span><span class="n">cache</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-24" name="__codelineno-0-24" href="#__codelineno-0-24"></a> <span class="n">config</span><span class="o">=</span><span class="n">CacheConfig</span><span class="p">(</span><span class="n">enabled</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">backend</span><span class="o">=</span><span class="s2">"memory"</span><span class="p">),</span>
|
||||
<a id="__codelineno-0-25" name="__codelineno-0-25" href="#__codelineno-0-25"></a> <span class="p">)</span>
|
||||
<a id="__codelineno-0-26" name="__codelineno-0-26" href="#__codelineno-0-26"></a>
|
||||
<a id="__codelineno-0-27" name="__codelineno-0-27" href="#__codelineno-0-27"></a>
|
||||
<a id="__codelineno-0-28" name="__codelineno-0-28" href="#__codelineno-0-28"></a><span class="nd">@asynccontextmanager</span>
|
||||
<a id="__codelineno-0-29" name="__codelineno-0-29" href="#__codelineno-0-29"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">lifespan</span><span class="p">(</span><span class="n">_app</span><span class="p">:</span> <span class="n">FastAPI</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-30" name="__codelineno-0-30" href="#__codelineno-0-30"></a> <span class="k">async</span> <span class="k">with</span> <span class="n">MongoConnectionManager</span><span class="o">.</span><span class="n">lifespan</span><span class="p">(</span>
|
||||
<a id="__codelineno-0-31" name="__codelineno-0-31" href="#__codelineno-0-31"></a> <span class="n">uri</span><span class="o">=</span><span class="s2">"mongodb://localhost:27017"</span><span class="p">,</span> <span class="n">db_name</span><span class="o">=</span><span class="s2">"shop"</span>
|
||||
<a id="__codelineno-0-32" name="__codelineno-0-32" href="#__codelineno-0-32"></a> <span class="p">):</span>
|
||||
<a id="__codelineno-0-33" name="__codelineno-0-33" href="#__codelineno-0-33"></a> <span class="k">await</span> <span class="n">ModelRegistry</span><span class="o">.</span><span class="n">initialize_all</span><span class="p">()</span>
|
||||
<a id="__codelineno-0-34" name="__codelineno-0-34" href="#__codelineno-0-34"></a> <span class="k">await</span> <span class="n">ModelRegistry</span><span class="o">.</span><span class="n">initialize_cache</span><span class="p">()</span> <span class="c1"># starts the TTL cleanup task</span>
|
||||
<a id="__codelineno-0-35" name="__codelineno-0-35" href="#__codelineno-0-35"></a> <span class="k">yield</span>
|
||||
<a id="__codelineno-0-36" name="__codelineno-0-36" href="#__codelineno-0-36"></a> <span class="k">await</span> <span class="n">ModelRegistry</span><span class="o">.</span><span class="n">shutdown_cache</span><span class="p">()</span> <span class="c1"># cancels it on exit</span>
|
||||
<a id="__codelineno-0-37" name="__codelineno-0-37" href="#__codelineno-0-37"></a>
|
||||
<a id="__codelineno-0-38" name="__codelineno-0-38" href="#__codelineno-0-38"></a>
|
||||
<a id="__codelineno-0-39" name="__codelineno-0-39" href="#__codelineno-0-39"></a><span class="n">app</span> <span class="o">=</span> <span class="n">FastAPI</span><span class="p">(</span><span class="n">lifespan</span><span class="o">=</span><span class="n">lifespan</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-40" name="__codelineno-0-40" href="#__codelineno-0-40"></a>
|
||||
<a id="__codelineno-0-41" name="__codelineno-0-41" href="#__codelineno-0-41"></a>
|
||||
<a id="__codelineno-0-42" name="__codelineno-0-42" href="#__codelineno-0-42"></a><span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/products/"</span><span class="p">,</span> <span class="n">response_model</span><span class="o">=</span><span class="n">Product</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-43" name="__codelineno-0-43" href="#__codelineno-0-43"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">create_product</span><span class="p">(</span><span class="n">product</span><span class="p">:</span> <span class="n">Product</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-44" name="__codelineno-0-44" href="#__codelineno-0-44"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">ProductRepo</span><span class="p">()</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">product</span><span class="p">)</span> <span class="c1"># created after connect()</span>
|
||||
<a id="__codelineno-0-45" name="__codelineno-0-45" href="#__codelineno-0-45"></a>
|
||||
<a id="__codelineno-0-46" name="__codelineno-0-46" href="#__codelineno-0-46"></a>
|
||||
<a id="__codelineno-0-47" name="__codelineno-0-47" href="#__codelineno-0-47"></a><span class="nd">@app</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"/products/</span><span class="si">{product_id}</span><span class="s2">"</span><span class="p">,</span> <span class="n">response_model</span><span class="o">=</span><span class="n">Product</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-48" name="__codelineno-0-48" href="#__codelineno-0-48"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">get_product</span><span class="p">(</span><span class="n">product_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-49" name="__codelineno-0-49" href="#__codelineno-0-49"></a> <span class="n">product</span> <span class="o">=</span> <span class="k">await</span> <span class="n">ProductRepo</span><span class="p">()</span><span class="o">.</span><span class="n">get_by_id</span><span class="p">(</span><span class="n">product_id</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-50" name="__codelineno-0-50" href="#__codelineno-0-50"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">product</span><span class="p">:</span>
|
||||
<a id="__codelineno-0-51" name="__codelineno-0-51" href="#__codelineno-0-51"></a> <span class="k">raise</span> <span class="n">HTTPException</span><span class="p">(</span><span class="n">status_code</span><span class="o">=</span><span class="mi">404</span><span class="p">,</span> <span class="n">detail</span><span class="o">=</span><span class="s2">"Product not found"</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-52" name="__codelineno-0-52" href="#__codelineno-0-52"></a> <span class="k">return</span> <span class="n">product</span>
|
||||
<a id="__codelineno-0-53" name="__codelineno-0-53" href="#__codelineno-0-53"></a>
|
||||
<a id="__codelineno-0-54" name="__codelineno-0-54" href="#__codelineno-0-54"></a>
|
||||
<a id="__codelineno-0-55" name="__codelineno-0-55" href="#__codelineno-0-55"></a><span class="nd">@app</span><span class="o">.</span><span class="n">put</span><span class="p">(</span><span class="s2">"/products/</span><span class="si">{product_id}</span><span class="s2">"</span><span class="p">,</span> <span class="n">response_model</span><span class="o">=</span><span class="n">Product</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-56" name="__codelineno-0-56" href="#__codelineno-0-56"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">update_product</span><span class="p">(</span><span class="n">product_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span> <span class="n">price</span><span class="p">:</span> <span class="nb">float</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-57" name="__codelineno-0-57" href="#__codelineno-0-57"></a> <span class="n">data</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
<a id="__codelineno-0-58" name="__codelineno-0-58" href="#__codelineno-0-58"></a> <span class="k">if</span> <span class="n">name</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<a id="__codelineno-0-59" name="__codelineno-0-59" href="#__codelineno-0-59"></a> <span class="n">data</span><span class="p">[</span><span class="s2">"name"</span><span class="p">]</span> <span class="o">=</span> <span class="n">name</span>
|
||||
<a id="__codelineno-0-60" name="__codelineno-0-60" href="#__codelineno-0-60"></a> <span class="k">if</span> <span class="n">price</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<a id="__codelineno-0-61" name="__codelineno-0-61" href="#__codelineno-0-61"></a> <span class="n">data</span><span class="p">[</span><span class="s2">"price"</span><span class="p">]</span> <span class="o">=</span> <span class="n">price</span>
|
||||
<a id="__codelineno-0-62" name="__codelineno-0-62" href="#__codelineno-0-62"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">ProductRepo</span><span class="p">()</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">product_id</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-63" name="__codelineno-0-63" href="#__codelineno-0-63"></a>
|
||||
<a id="__codelineno-0-64" name="__codelineno-0-64" href="#__codelineno-0-64"></a>
|
||||
<a id="__codelineno-0-65" name="__codelineno-0-65" href="#__codelineno-0-65"></a><span class="c1"># Outside request handlers:</span>
|
||||
<a id="__codelineno-0-66" name="__codelineno-0-66" href="#__codelineno-0-66"></a><span class="c1"># await ProductRepo().warm_cache([object_id_1, object_id_2]) # pre-load n ids -> int</span>
|
||||
<a id="__codelineno-0-67" name="__codelineno-0-67" href="#__codelineno-0-67"></a><span class="c1"># await ProductRepo().invalidate_cache(object_id_3) # manual eviction</span>
|
||||
</code></pre></div>
|
||||
<hr />
|
||||
<h2 id="3-using-the-repository">3️⃣ Using the Repository</h2>
|
||||
<div class="language-python highlight"><span class="filename">Python</span><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="n">repo</span> <span class="o">=</span> <span class="n">ProductRepo</span><span class="p">()</span>
|
||||
<a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="c1"># Create – automatically caches the new document</span>
|
||||
<a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="n">product</span> <span class="o">=</span> <span class="k">await</span> <span class="n">repo</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="n">Product</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"Widget"</span><span class="p">,</span> <span class="n">price</span><span class="o">=</span><span class="mf">9.99</span><span class="p">))</span>
|
||||
<a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a>
|
||||
<a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="c1"># Normal read – will hit the cache after the first DB fetch</span>
|
||||
<a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a><span class="n">fetched</span> <span class="o">=</span> <span class="k">await</span> <span class="n">repo</span><span class="o">.</span><span class="n">get_by_id</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
|
||||
<a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a>
|
||||
<a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a><span class="c1"># Update – cache entry is refreshed</span>
|
||||
<a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a><span class="k">await</span> <span class="n">repo</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">id</span><span class="p">,</span> <span class="p">{</span><span class="s2">"price"</span><span class="p">:</span> <span class="mf">8.99</span><span class="p">})</span>
|
||||
<a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a>
|
||||
<a id="__codelineno-1-11" name="__codelineno-1-11" href="#__codelineno-1-11"></a><span class="c1"># Delete – cache entry removed</span>
|
||||
<a id="__codelineno-1-12" name="__codelineno-1-12" href="#__codelineno-1-12"></a><span class="k">await</span> <span class="n">repo</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
|
||||
<a id="__codelineno-1-13" name="__codelineno-1-13" href="#__codelineno-1-13"></a>
|
||||
<a id="__codelineno-1-14" name="__codelineno-1-14" href="#__codelineno-1-14"></a><span class="c1"># Warm a set of IDs in advance (e.g., during a bulk load)</span>
|
||||
<a id="__codelineno-1-15" name="__codelineno-1-15" href="#__codelineno-1-15"></a><span class="k">await</span> <span class="n">repo</span><span class="o">.</span><span class="n">warm_cache</span><span class="p">([</span><span class="n">ObjectId</span><span class="p">(</span><span class="s2">"..."</span><span class="p">),</span> <span class="n">ObjectId</span><span class="p">(</span><span class="s2">"..."</span><span class="p">)])</span>
|
||||
<h2 id="redis-backend">🔄 Redis Backend</h2>
|
||||
<p>Swap the backend — the repository code stays identical:</p>
|
||||
<div class="language-python highlight"><span class="filename">Python</span><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">mongo_ops.cache</span><span class="w"> </span><span class="kn">import</span> <span class="n">RedisCacheBackend</span>
|
||||
<a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">redis.asyncio</span><span class="w"> </span><span class="kn">import</span> <span class="n">Redis</span>
|
||||
<a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a>
|
||||
<a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="n">redis_client</span> <span class="o">=</span> <span class="n">Redis</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">6379</span><span class="p">)</span>
|
||||
<a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="n">redis_backend</span> <span class="o">=</span> <span class="n">RedisCacheBackend</span><span class="p">(</span><span class="n">redis_client</span><span class="p">,</span> <span class="n">key_prefix</span><span class="o">=</span><span class="s2">"prod:"</span><span class="p">)</span>
|
||||
<a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a>
|
||||
<a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a><span class="n">ModelRegistry</span><span class="o">.</span><span class="n">set_cache_backend</span><span class="p">(</span><span class="n">redis_backend</span><span class="p">)</span> <span class="c1"># for the lifecycle in lifespan()</span>
|
||||
<a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a>
|
||||
<a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a><span class="k">class</span><span class="w"> </span><span class="nc">ProductRepo</span><span class="p">(</span><span class="n">CachedBaseRepository</span><span class="p">[</span><span class="n">Product</span><span class="p">]):</span>
|
||||
<a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<a id="__codelineno-1-11" name="__codelineno-1-11" href="#__codelineno-1-11"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span>
|
||||
<a id="__codelineno-1-12" name="__codelineno-1-12" href="#__codelineno-1-12"></a> <span class="n">collection_name</span><span class="o">=</span><span class="s2">"products"</span><span class="p">,</span>
|
||||
<a id="__codelineno-1-13" name="__codelineno-1-13" href="#__codelineno-1-13"></a> <span class="n">model</span><span class="o">=</span><span class="n">Product</span><span class="p">,</span>
|
||||
<a id="__codelineno-1-14" name="__codelineno-1-14" href="#__codelineno-1-14"></a> <span class="n">cache_backend</span><span class="o">=</span><span class="n">redis_backend</span><span class="p">,</span>
|
||||
<a id="__codelineno-1-15" name="__codelineno-1-15" href="#__codelineno-1-15"></a> <span class="n">config</span><span class="o">=</span><span class="n">CacheConfig</span><span class="p">(</span><span class="n">enabled</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">backend</span><span class="o">=</span><span class="s2">"redis"</span><span class="p">),</span>
|
||||
<a id="__codelineno-1-16" name="__codelineno-1-16" href="#__codelineno-1-16"></a> <span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<hr />
|
||||
<h2 id="4-redis-backend-optional">4️⃣ Redis Backend (optional)</h2>
|
||||
<p>If you prefer a distributed cache, swap the backend:</p>
|
||||
<div class="language-python highlight"><span class="filename">Python</span><pre><span></span><code><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="kn">from</span><span class="w"> </span><span class="nn">mongo_ops.cache</span><span class="w"> </span><span class="kn">import</span> <span class="n">RedisCacheBackend</span>
|
||||
<a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">redis.asyncio</span><span class="w"> </span><span class="kn">import</span> <span class="n">Redis</span>
|
||||
<a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a>
|
||||
<a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a><span class="n">redis_client</span> <span class="o">=</span> <span class="n">Redis</span><span class="p">(</span><span class="n">host</span><span class="o">=</span><span class="s2">"localhost"</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">6379</span><span class="p">)</span>
|
||||
<a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a><span class="n">redis_backend</span> <span class="o">=</span> <span class="n">RedisCacheBackend</span><span class="p">(</span><span class="n">redis_client</span><span class="p">,</span> <span class="n">key_prefix</span><span class="o">=</span><span class="s2">"prod:"</span><span class="p">)</span>
|
||||
<a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a><span class="n">ModelRegistry</span><span class="o">.</span><span class="n">set_cache_backend</span><span class="p">(</span><span class="n">redis_backend</span><span class="p">)</span>
|
||||
</code></pre></div>
|
||||
<p>The repository code stays the same – just pass the <code>redis_backend</code> instance to <code>CachedBaseRepository</code>.</p>
|
||||
<hr />
|
||||
<h2 id="5-when-to-use-caching">5️⃣ When to Use Caching</h2>
|
||||
<h2 id="tips">💡 Tips</h2>
|
||||
<ul>
|
||||
<li>Frequently accessed documents (e.g., product details, configuration settings).</li>
|
||||
<li>Low‑write‑to‑read ratios where cache invalidation cost is acceptable.</li>
|
||||
<li>Distributed deployments where a shared Redis cache syncs invalidations via pub/sub.</li>
|
||||
<li>Cache keys are <code>"{key_prefix}{id}"</code> (default prefix <code>"products:"</code>). <code>clear_pattern("products:*")</code> wipes a whole collection's entries.</li>
|
||||
<li>Values are JSON-encoded (<code>json.dumps(obj, default=str)</code>) — nested models inside a cached document are stored as dicts, not objects.</li>
|
||||
<li>Enable/disable per repository with <code>CacheConfig(enabled=False)</code>; a disabled repo bypasses the cache entirely.</li>
|
||||
<li>Distinguish the two <code>initialize*</code> calls: <code>initialize_cache()</code> starts the backend task; <code>initialize_all()</code> creates indexes. Both belong in the lifespan, <strong>after</strong> <code>connect()</code>.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="6-related-docs">6️⃣ Related Docs</h2>
|
||||
<h2 id="related">Related</h2>
|
||||
<ul>
|
||||
<li><strong>Core Components</strong> – see <code>docs/02_components.md</code> for the <code>CacheBackend</code> abstraction.</li>
|
||||
<li><strong>Best Practices</strong> – remember to call <code>ModelRegistry.initialize_cache()</code> after DB connection.</li>
|
||||
<li><a href="../11_cache_lifecycle/">11 – Cache lifecycle</a> · <a href="../10_cache_and_population/">10 – Cache + population</a> · <a href="../../02_components/">Components: cache</a></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><em>Feel free to adapt the TTL, max entries, and backend to your workload.</em></p>
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user