docs: collect refreshed mongo-ops wiki site (API-correct overhaul, v0.1.5)
This commit is contained in:
@@ -457,7 +457,7 @@
|
||||
|
||||
|
||||
<span class="md-ellipsis">
|
||||
02 components
|
||||
Core Components
|
||||
|
||||
</span>
|
||||
|
||||
@@ -828,7 +828,7 @@
|
||||
<li class="md-nav__item">
|
||||
<a href="#whats-new" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
📦 What’s New?
|
||||
📦 What's New?
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -850,6 +850,15 @@
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#related" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Related
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@@ -1027,10 +1036,9 @@
|
||||
|
||||
|
||||
<h1 id="use-case-12-using-transactionmanagerexecute_transaction">Use Case 12: Using <code>TransactionManager.execute_transaction</code></h1>
|
||||
<p><strong>Scenario:</strong>
|
||||
You need to perform several writes across different collections atomically (e.g., creating an <code>Order</code> and updating the <code>Inventory</code> for each ordered item). The low‑level <code>start_session</code> context manager works, but the high‑level <code>execute_transaction</code> helper makes the code cleaner and returns all operation results in a list.</p>
|
||||
<p><strong>Scenario:</strong> Perform several writes across different collections atomically — e.g., create an <code>Order</code> <strong>and</strong> decrement <code>Inventory</code>. The low-level <code>start_session</code> context works, but <code>execute_transaction</code> collects results from a list of async operations.</p>
|
||||
<hr />
|
||||
<h2 id="whats-new">📦 What’s New?</h2>
|
||||
<h2 id="whats-new">📦 What's New?</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -1041,112 +1049,113 @@ You need to perform several writes across different collections atomically (e.g.
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>TransactionManager.execute_transaction</code></td>
|
||||
<td>Accepts a list of async callables (each receiving a <code>session</code>) and executes them inside a single MongoDB transaction. Returns a list of each callable’s result.</td>
|
||||
<td>Runs a list of async callables (each receives a session) inside one transaction; returns the result of each callable, in order.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Automatic rollback</td>
|
||||
<td>If any operation raises an exception, the transaction is aborted and the exception propagates.</td>
|
||||
<td>Any raised exception aborts the transaction and propagates to the caller.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>start_session</code></td>
|
||||
<td>The underlying async context manager <code>async with TransactionManager.start_session() as session:</code>.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<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">mongo_ops</span><span class="w"> </span><span class="kn">import</span> <span class="n">MongoConnectionManager</span><span class="p">,</span> <span class="n">ModelRegistry</span>
|
||||
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="kn">from</span><span class="w"> </span><span class="nn">mongo_ops.transactions</span><span class="w"> </span><span class="kn">import</span> <span class="n">TransactionManager</span>
|
||||
<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">mongo_ops.repository</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseRepository</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.models</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseDocument</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">bson</span><span class="w"> </span><span class="kn">import</span> <span class="n">ObjectId</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><span class="c1"># ----------------------------------------------------------------------</span>
|
||||
<a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a><span class="c1"># 1️⃣ Define simple models</span>
|
||||
<a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a><span class="c1"># ----------------------------------------------------------------------</span>
|
||||
<a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a><span class="k">class</span><span class="w"> </span><span class="nc">Order</span><span class="p">(</span><span class="n">BaseDocument</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a> <span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span>
|
||||
<a id="__codelineno-0-12" name="__codelineno-0-12" href="#__codelineno-0-12"></a> <span class="n">items</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">dict</span><span class="p">]</span> <span class="c1"># [{"product_id": ObjectId, "qty": int}]</span>
|
||||
<a id="__codelineno-0-13" name="__codelineno-0-13" href="#__codelineno-0-13"></a> <span class="n">total</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">0.0</span>
|
||||
<a id="__codelineno-0-14" name="__codelineno-0-14" href="#__codelineno-0-14"></a>
|
||||
<a id="__codelineno-0-15" name="__codelineno-0-15" href="#__codelineno-0-15"></a><span class="k">class</span><span class="w"> </span><span class="nc">Inventory</span><span class="p">(</span><span class="n">BaseDocument</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-16" name="__codelineno-0-16" href="#__codelineno-0-16"></a> <span class="n">product_id</span><span class="p">:</span> <span class="n">ObjectId</span>
|
||||
<a id="__codelineno-0-17" name="__codelineno-0-17" href="#__codelineno-0-17"></a> <span class="n">quantity</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
<a id="__codelineno-0-18" name="__codelineno-0-18" href="#__codelineno-0-18"></a>
|
||||
<a id="__codelineno-0-19" name="__codelineno-0-19" href="#__codelineno-0-19"></a><span class="c1"># ----------------------------------------------------------------------</span>
|
||||
<a id="__codelineno-0-20" name="__codelineno-0-20" href="#__codelineno-0-20"></a><span class="c1"># 2️⃣ Repositories</span>
|
||||
<a id="__codelineno-0-21" name="__codelineno-0-21" href="#__codelineno-0-21"></a><span class="c1"># ----------------------------------------------------------------------</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">OrderRepo</span><span class="p">(</span><span class="n">BaseRepository</span><span class="p">[</span><span class="n">Order</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><span class="s2">"orders"</span><span class="p">,</span> <span class="n">Order</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-25" name="__codelineno-0-25" href="#__codelineno-0-25"></a>
|
||||
<a id="__codelineno-0-26" name="__codelineno-0-26" href="#__codelineno-0-26"></a><span class="k">class</span><span class="w"> </span><span class="nc">InventoryRepo</span><span class="p">(</span><span class="n">BaseRepository</span><span class="p">[</span><span class="n">Inventory</span><span class="p">]):</span>
|
||||
<a id="__codelineno-0-27" name="__codelineno-0-27" href="#__codelineno-0-27"></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-28" name="__codelineno-0-28" href="#__codelineno-0-28"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="s2">"inventory"</span><span class="p">,</span> <span class="n">Inventory</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-29" name="__codelineno-0-29" href="#__codelineno-0-29"></a>
|
||||
<a id="__codelineno-0-30" name="__codelineno-0-30" href="#__codelineno-0-30"></a><span class="n">order_repo</span> <span class="o">=</span> <span class="n">OrderRepo</span><span class="p">()</span>
|
||||
<a id="__codelineno-0-31" name="__codelineno-0-31" href="#__codelineno-0-31"></a><span class="n">inv_repo</span> <span class="o">=</span> <span class="n">InventoryRepo</span><span class="p">()</span>
|
||||
<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><span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime</span>
|
||||
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>
|
||||
<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">bson</span><span class="w"> </span><span class="kn">import</span> <span class="n">ObjectId</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">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-6" name="__codelineno-0-6" href="#__codelineno-0-6"></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-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a><span class="kn">from</span><span class="w"> </span><span class="nn">mongo_ops.repository</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseRepository</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.transactions</span><span class="w"> </span><span class="kn">import</span> <span class="n">TransactionManager</span>
|
||||
<a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a>
|
||||
<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"># 1. Models</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">Order</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">user_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">""</span>
|
||||
<a id="__codelineno-0-14" name="__codelineno-0-14" href="#__codelineno-0-14"></a> <span class="n">items</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">dict</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1"># [{"product_id": ObjectId, "qty": int}]</span>
|
||||
<a id="__codelineno-0-15" name="__codelineno-0-15" href="#__codelineno-0-15"></a> <span class="n">total</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">0.0</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">Inventory</span><span class="p">(</span><span class="n">BaseDocument</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-19" name="__codelineno-0-19" href="#__codelineno-0-19"></a> <span class="n">product_id</span><span class="p">:</span> <span class="n">ObjectId</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<a id="__codelineno-0-20" name="__codelineno-0-20" href="#__codelineno-0-20"></a> <span class="n">quantity</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
<a id="__codelineno-0-21" name="__codelineno-0-21" href="#__codelineno-0-21"></a>
|
||||
<a id="__codelineno-0-22" name="__codelineno-0-22" href="#__codelineno-0-22"></a>
|
||||
<a id="__codelineno-0-23" name="__codelineno-0-23" href="#__codelineno-0-23"></a><span class="c1"># 2. Repositories (constructed inside the lifespan — after connect()).</span>
|
||||
<a id="__codelineno-0-24" name="__codelineno-0-24" href="#__codelineno-0-24"></a><span class="k">class</span><span class="w"> </span><span class="nc">OrderRepo</span><span class="p">(</span><span class="n">BaseRepository</span><span class="p">[</span><span class="n">Order</span><span class="p">]):</span>
|
||||
<a id="__codelineno-0-25" name="__codelineno-0-25" href="#__codelineno-0-25"></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-26" name="__codelineno-0-26" href="#__codelineno-0-26"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="s2">"orders"</span><span class="p">,</span> <span class="n">Order</span><span class="p">)</span>
|
||||
<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>
|
||||
<a id="__codelineno-0-29" name="__codelineno-0-29" href="#__codelineno-0-29"></a><span class="k">class</span><span class="w"> </span><span class="nc">InventoryRepo</span><span class="p">(</span><span class="n">BaseRepository</span><span class="p">[</span><span class="n">Inventory</span><span class="p">]):</span>
|
||||
<a id="__codelineno-0-30" name="__codelineno-0-30" href="#__codelineno-0-30"></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-31" name="__codelineno-0-31" href="#__codelineno-0-31"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="s2">"inventory"</span><span class="p">,</span> <span class="n">Inventory</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-32" name="__codelineno-0-32" href="#__codelineno-0-32"></a>
|
||||
<a id="__codelineno-0-33" name="__codelineno-0-33" href="#__codelineno-0-33"></a><span class="c1"># ----------------------------------------------------------------------</span>
|
||||
<a id="__codelineno-0-34" name="__codelineno-0-34" href="#__codelineno-0-34"></a><span class="c1"># 3️⃣ Transaction helper</span>
|
||||
<a id="__codelineno-0-35" name="__codelineno-0-35" href="#__codelineno-0-35"></a><span class="c1"># ----------------------------------------------------------------------</span>
|
||||
<a id="__codelineno-0-36" name="__codelineno-0-36" href="#__codelineno-0-36"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">create_order_with_inventory</span><span class="p">(</span><span class="n">order</span><span class="p">:</span> <span class="n">Order</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-37" name="__codelineno-0-37" href="#__codelineno-0-37"></a> <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">insert_order</span><span class="p">(</span><span class="n">session</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-38" name="__codelineno-0-38" href="#__codelineno-0-38"></a> <span class="c1"># Insert the order document</span>
|
||||
<a id="__codelineno-0-39" name="__codelineno-0-39" href="#__codelineno-0-39"></a> <span class="n">doc</span> <span class="o">=</span> <span class="n">order</span><span class="o">.</span><span class="n">model_dump</span><span class="p">(</span><span class="n">exclude</span><span class="o">=</span><span class="p">{</span><span class="s2">"id"</span><span class="p">},</span> <span class="n">exclude_none</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-40" name="__codelineno-0-40" href="#__codelineno-0-40"></a> <span class="n">doc</span><span class="p">[</span><span class="s2">"created_at"</span><span class="p">]</span> <span class="o">=</span> <span class="n">doc</span><span class="p">[</span><span class="s2">"updated_at"</span><span class="p">]</span> <span class="o">=</span> <span class="nb">__import__</span><span class="p">(</span><span class="s2">"datetime"</span><span class="p">)</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">utcnow</span><span class="p">()</span>
|
||||
<a id="__codelineno-0-41" name="__codelineno-0-41" href="#__codelineno-0-41"></a> <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">order_repo</span><span class="o">.</span><span class="n">collection</span><span class="o">.</span><span class="n">insert_one</span><span class="p">(</span><span class="n">doc</span><span class="p">,</span> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-42" name="__codelineno-0-42" href="#__codelineno-0-42"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">order_repo</span><span class="o">.</span><span class="n">collection</span><span class="o">.</span><span class="n">find_one</span><span class="p">({</span><span class="s2">"_id"</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">inserted_id</span><span class="p">},</span> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-43" name="__codelineno-0-43" href="#__codelineno-0-43"></a>
|
||||
<a id="__codelineno-0-44" name="__codelineno-0-44" href="#__codelineno-0-44"></a> <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">update_inventory</span><span class="p">(</span><span class="n">session</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-45" name="__codelineno-0-45" href="#__codelineno-0-45"></a> <span class="c1"># Decrease quantity for each ordered item</span>
|
||||
<a id="__codelineno-0-46" name="__codelineno-0-46" href="#__codelineno-0-46"></a> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">order</span><span class="o">.</span><span class="n">items</span><span class="p">:</span>
|
||||
<a id="__codelineno-0-47" name="__codelineno-0-47" href="#__codelineno-0-47"></a> <span class="k">await</span> <span class="n">inv_repo</span><span class="o">.</span><span class="n">collection</span><span class="o">.</span><span class="n">update_one</span><span class="p">(</span>
|
||||
<a id="__codelineno-0-48" name="__codelineno-0-48" href="#__codelineno-0-48"></a> <span class="p">{</span><span class="s2">"product_id"</span><span class="p">:</span> <span class="n">ObjectId</span><span class="p">(</span><span class="n">item</span><span class="p">[</span><span class="s2">"product_id"</span><span class="p">])},</span>
|
||||
<a id="__codelineno-0-49" name="__codelineno-0-49" href="#__codelineno-0-49"></a> <span class="p">{</span><span class="s2">"$inc"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"quantity"</span><span class="p">:</span> <span class="o">-</span><span class="n">item</span><span class="p">[</span><span class="s2">"qty"</span><span class="p">]}},</span>
|
||||
<a id="__codelineno-0-50" name="__codelineno-0-50" href="#__codelineno-0-50"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-51" name="__codelineno-0-51" href="#__codelineno-0-51"></a> <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="s2">"inventory-updated"</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> <span class="c1"># Execute both operations atomically</span>
|
||||
<a id="__codelineno-0-55" name="__codelineno-0-55" href="#__codelineno-0-55"></a> <span class="n">results</span> <span class="o">=</span> <span class="k">await</span> <span class="n">TransactionManager</span><span class="o">.</span><span class="n">execute_transaction</span><span class="p">([</span>
|
||||
<a id="__codelineno-0-56" name="__codelineno-0-56" href="#__codelineno-0-56"></a> <span class="k">lambda</span> <span class="n">s</span><span class="p">:</span> <span class="n">insert_order</span><span class="p">(</span><span class="n">s</span><span class="p">),</span>
|
||||
<a id="__codelineno-0-57" name="__codelineno-0-57" href="#__codelineno-0-57"></a> <span class="k">lambda</span> <span class="n">s</span><span class="p">:</span> <span class="n">update_inventory</span><span class="p">(</span><span class="n">s</span><span class="p">),</span>
|
||||
<a id="__codelineno-0-58" name="__codelineno-0-58" href="#__codelineno-0-58"></a> <span class="p">])</span>
|
||||
<a id="__codelineno-0-59" name="__codelineno-0-59" href="#__codelineno-0-59"></a> <span class="c1"># `results[0]` is the created order document, `results[1]` is the marker string</span>
|
||||
<a id="__codelineno-0-60" name="__codelineno-0-60" href="#__codelineno-0-60"></a> <span class="k">return</span> <span class="n">results</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
||||
<a id="__codelineno-0-61" name="__codelineno-0-61" href="#__codelineno-0-61"></a>
|
||||
<a id="__codelineno-0-62" name="__codelineno-0-62" href="#__codelineno-0-62"></a><span class="c1"># ----------------------------------------------------------------------</span>
|
||||
<a id="__codelineno-0-63" name="__codelineno-0-63" href="#__codelineno-0-63"></a><span class="c1"># 4️⃣ FastAPI lifespan – initialise DB and run the example endpoint</span>
|
||||
<a id="__codelineno-0-64" name="__codelineno-0-64" href="#__codelineno-0-64"></a><span class="c1"># ----------------------------------------------------------------------</span>
|
||||
<a id="__codelineno-0-65" name="__codelineno-0-65" href="#__codelineno-0-65"></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-66" name="__codelineno-0-66" href="#__codelineno-0-66"></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-67" name="__codelineno-0-67" href="#__codelineno-0-67"></a>
|
||||
<a id="__codelineno-0-68" name="__codelineno-0-68" href="#__codelineno-0-68"></a><span class="n">app</span> <span class="o">=</span> <span class="n">FastAPI</span><span class="p">()</span>
|
||||
<a id="__codelineno-0-33" name="__codelineno-0-33" href="#__codelineno-0-33"></a>
|
||||
<a id="__codelineno-0-34" name="__codelineno-0-34" href="#__codelineno-0-34"></a><span class="c1"># 3. The atomic operation.</span>
|
||||
<a id="__codelineno-0-35" name="__codelineno-0-35" href="#__codelineno-0-35"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">create_order_with_inventory</span><span class="p">(</span><span class="n">order</span><span class="p">:</span> <span class="n">Order</span><span class="p">,</span> <span class="n">order_repo</span><span class="p">:</span> <span class="n">OrderRepo</span><span class="p">,</span> <span class="n">inv_repo</span><span class="p">:</span> <span class="n">InventoryRepo</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-36" name="__codelineno-0-36" href="#__codelineno-0-36"></a> <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">insert_order</span><span class="p">(</span><span class="n">session</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-37" name="__codelineno-0-37" href="#__codelineno-0-37"></a> <span class="n">doc</span> <span class="o">=</span> <span class="n">order</span><span class="o">.</span><span class="n">model_dump</span><span class="p">(</span><span class="n">exclude</span><span class="o">=</span><span class="p">{</span><span class="s2">"id"</span><span class="p">},</span> <span class="n">exclude_none</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-38" name="__codelineno-0-38" href="#__codelineno-0-38"></a> <span class="n">doc</span><span class="p">[</span><span class="s2">"created_at"</span><span class="p">]</span> <span class="o">=</span> <span class="n">doc</span><span class="p">[</span><span class="s2">"updated_at"</span><span class="p">]</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">utcnow</span><span class="p">()</span>
|
||||
<a id="__codelineno-0-39" name="__codelineno-0-39" href="#__codelineno-0-39"></a> <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">order_repo</span><span class="o">.</span><span class="n">collection</span><span class="o">.</span><span class="n">insert_one</span><span class="p">(</span><span class="n">doc</span><span class="p">,</span> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-40" name="__codelineno-0-40" href="#__codelineno-0-40"></a> <span class="k">return</span> <span class="k">await</span> <span class="n">order_repo</span><span class="o">.</span><span class="n">collection</span><span class="o">.</span><span class="n">find_one</span><span class="p">({</span><span class="s2">"_id"</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">inserted_id</span><span class="p">},</span> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">)</span>
|
||||
<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="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">update_inventory</span><span class="p">(</span><span class="n">session</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-43" name="__codelineno-0-43" href="#__codelineno-0-43"></a> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">order</span><span class="o">.</span><span class="n">items</span><span class="p">:</span>
|
||||
<a id="__codelineno-0-44" name="__codelineno-0-44" href="#__codelineno-0-44"></a> <span class="k">await</span> <span class="n">inv_repo</span><span class="o">.</span><span class="n">collection</span><span class="o">.</span><span class="n">update_one</span><span class="p">(</span>
|
||||
<a id="__codelineno-0-45" name="__codelineno-0-45" href="#__codelineno-0-45"></a> <span class="p">{</span><span class="s2">"product_id"</span><span class="p">:</span> <span class="n">ObjectId</span><span class="p">(</span><span class="n">item</span><span class="p">[</span><span class="s2">"product_id"</span><span class="p">])},</span>
|
||||
<a id="__codelineno-0-46" name="__codelineno-0-46" href="#__codelineno-0-46"></a> <span class="p">{</span><span class="s2">"$inc"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"quantity"</span><span class="p">:</span> <span class="o">-</span><span class="n">item</span><span class="p">[</span><span class="s2">"qty"</span><span class="p">]}},</span>
|
||||
<a id="__codelineno-0-47" name="__codelineno-0-47" href="#__codelineno-0-47"></a> <span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-48" name="__codelineno-0-48" href="#__codelineno-0-48"></a> <span class="p">)</span>
|
||||
<a id="__codelineno-0-49" name="__codelineno-0-49" href="#__codelineno-0-49"></a> <span class="k">return</span> <span class="s2">"inventory-updated"</span>
|
||||
<a id="__codelineno-0-50" name="__codelineno-0-50" href="#__codelineno-0-50"></a>
|
||||
<a id="__codelineno-0-51" name="__codelineno-0-51" href="#__codelineno-0-51"></a> <span class="n">results</span> <span class="o">=</span> <span class="k">await</span> <span class="n">TransactionManager</span><span class="o">.</span><span class="n">execute_transaction</span><span class="p">(</span>
|
||||
<a id="__codelineno-0-52" name="__codelineno-0-52" href="#__codelineno-0-52"></a> <span class="p">[</span><span class="n">insert_order</span><span class="p">,</span> <span class="n">update_inventory</span><span class="p">]</span>
|
||||
<a id="__codelineno-0-53" name="__codelineno-0-53" href="#__codelineno-0-53"></a> <span class="p">)</span>
|
||||
<a id="__codelineno-0-54" name="__codelineno-0-54" href="#__codelineno-0-54"></a> <span class="k">return</span> <span class="n">results</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># created order document; results[1] == "inventory-updated"</span>
|
||||
<a id="__codelineno-0-55" name="__codelineno-0-55" href="#__codelineno-0-55"></a>
|
||||
<a id="__codelineno-0-56" name="__codelineno-0-56" href="#__codelineno-0-56"></a>
|
||||
<a id="__codelineno-0-57" name="__codelineno-0-57" href="#__codelineno-0-57"></a><span class="c1"># 4. FastAPI wiring.</span>
|
||||
<a id="__codelineno-0-58" name="__codelineno-0-58" href="#__codelineno-0-58"></a><span class="n">app</span> <span class="o">=</span> <span class="n">FastAPI</span><span class="p">()</span>
|
||||
<a id="__codelineno-0-59" name="__codelineno-0-59" href="#__codelineno-0-59"></a>
|
||||
<a id="__codelineno-0-60" name="__codelineno-0-60" href="#__codelineno-0-60"></a>
|
||||
<a id="__codelineno-0-61" name="__codelineno-0-61" href="#__codelineno-0-61"></a><span class="nd">@asynccontextmanager</span>
|
||||
<a id="__codelineno-0-62" name="__codelineno-0-62" href="#__codelineno-0-62"></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-63" name="__codelineno-0-63" href="#__codelineno-0-63"></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-64" name="__codelineno-0-64" href="#__codelineno-0-64"></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-65" name="__codelineno-0-65" href="#__codelineno-0-65"></a> <span class="p">):</span>
|
||||
<a id="__codelineno-0-66" name="__codelineno-0-66" href="#__codelineno-0-66"></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-67" name="__codelineno-0-67" href="#__codelineno-0-67"></a> <span class="k">yield</span>
|
||||
<a id="__codelineno-0-68" name="__codelineno-0-68" href="#__codelineno-0-68"></a>
|
||||
<a id="__codelineno-0-69" name="__codelineno-0-69" href="#__codelineno-0-69"></a>
|
||||
<a id="__codelineno-0-70" name="__codelineno-0-70" href="#__codelineno-0-70"></a><span class="nd">@asynccontextmanager</span>
|
||||
<a id="__codelineno-0-71" name="__codelineno-0-71" href="#__codelineno-0-71"></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-72" name="__codelineno-0-72" href="#__codelineno-0-72"></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-73" name="__codelineno-0-73" href="#__codelineno-0-73"></a> <span class="n">uri</span><span class="o">=</span><span class="s2">"mongodb://localhost:27017"</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-74" name="__codelineno-0-74" href="#__codelineno-0-74"></a> <span class="n">db_name</span><span class="o">=</span><span class="s2">"shop"</span><span class="p">,</span>
|
||||
<a id="__codelineno-0-75" name="__codelineno-0-75" href="#__codelineno-0-75"></a> <span class="p">):</span>
|
||||
<a id="__codelineno-0-76" name="__codelineno-0-76" href="#__codelineno-0-76"></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-77" name="__codelineno-0-77" href="#__codelineno-0-77"></a> <span class="k">yield</span>
|
||||
<a id="__codelineno-0-78" name="__codelineno-0-78" href="#__codelineno-0-78"></a>
|
||||
<a id="__codelineno-0-79" name="__codelineno-0-79" href="#__codelineno-0-79"></a><span class="n">app</span><span class="o">.</span><span class="n">lifespan</span> <span class="o">=</span> <span class="n">lifespan</span>
|
||||
<a id="__codelineno-0-80" name="__codelineno-0-80" href="#__codelineno-0-80"></a>
|
||||
<a id="__codelineno-0-81" name="__codelineno-0-81" href="#__codelineno-0-81"></a><span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/orders/"</span><span class="p">,</span> <span class="n">response_model</span><span class="o">=</span><span class="n">Order</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-82" name="__codelineno-0-82" href="#__codelineno-0-82"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">create_order</span><span class="p">(</span><span class="n">order</span><span class="p">:</span> <span class="n">Order</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-83" name="__codelineno-0-83" href="#__codelineno-0-83"></a> <span class="n">created</span> <span class="o">=</span> <span class="k">await</span> <span class="n">create_order_with_inventory</span><span class="p">(</span><span class="n">order</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-84" name="__codelineno-0-84" href="#__codelineno-0-84"></a> <span class="k">if</span> <span class="n">created</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<a id="__codelineno-0-85" name="__codelineno-0-85" href="#__codelineno-0-85"></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">400</span><span class="p">,</span> <span class="n">detail</span><span class="o">=</span><span class="s2">"Transaction failed"</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-86" name="__codelineno-0-86" href="#__codelineno-0-86"></a> <span class="k">return</span> <span class="n">created</span>
|
||||
<a id="__codelineno-0-70" name="__codelineno-0-70" href="#__codelineno-0-70"></a><span class="n">app</span><span class="o">.</span><span class="n">lifespan</span> <span class="o">=</span> <span class="n">lifespan</span>
|
||||
<a id="__codelineno-0-71" name="__codelineno-0-71" href="#__codelineno-0-71"></a>
|
||||
<a id="__codelineno-0-72" name="__codelineno-0-72" href="#__codelineno-0-72"></a>
|
||||
<a id="__codelineno-0-73" name="__codelineno-0-73" href="#__codelineno-0-73"></a><span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/orders/"</span><span class="p">,</span> <span class="n">response_model</span><span class="o">=</span><span class="n">Order</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-74" name="__codelineno-0-74" href="#__codelineno-0-74"></a><span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">create_order</span><span class="p">(</span><span class="n">order</span><span class="p">:</span> <span class="n">Order</span><span class="p">):</span>
|
||||
<a id="__codelineno-0-75" name="__codelineno-0-75" href="#__codelineno-0-75"></a> <span class="n">created</span> <span class="o">=</span> <span class="k">await</span> <span class="n">create_order_with_inventory</span><span class="p">(</span><span class="n">order</span><span class="p">,</span> <span class="n">OrderRepo</span><span class="p">(),</span> <span class="n">InventoryRepo</span><span class="p">())</span>
|
||||
<a id="__codelineno-0-76" name="__codelineno-0-76" href="#__codelineno-0-76"></a> <span class="k">if</span> <span class="n">created</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<a id="__codelineno-0-77" name="__codelineno-0-77" href="#__codelineno-0-77"></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">400</span><span class="p">,</span> <span class="n">detail</span><span class="o">=</span><span class="s2">"Transaction failed"</span><span class="p">)</span>
|
||||
<a id="__codelineno-0-78" name="__codelineno-0-78" href="#__codelineno-0-78"></a> <span class="k">return</span> <span class="n">created</span>
|
||||
</code></pre></div>
|
||||
<hr />
|
||||
<h2 id="tips">💡 Tips</h2>
|
||||
<ul>
|
||||
<li><strong>Return values:</strong> Each callable can return whatever you need (inserted document, stats, etc.). The helper collects them in order.</li>
|
||||
<li><strong>Error handling:</strong> Raising any exception inside a callable will abort the transaction automatically.</li>
|
||||
<li><strong>Read‑only ops:</strong> You can also run queries inside the transaction – just pass <code>session=session</code> to the <code>find_one</code>/<code>find</code> calls.</li>
|
||||
<li><strong>Testing:</strong> In unit tests you can mock <code>TransactionManager.start_session</code> to ensure the helpers are called.</li>
|
||||
<li><strong>Return values:</strong> each callable can return whatever you need; results are collected in the same order.</li>
|
||||
<li><strong>Errors:</strong> raise inside any callable → the whole transaction aborts (session rolls back) and the exception propagates.</li>
|
||||
<li><strong>Reads inside a transaction:</strong> pass <code>session=session</code> to <code>find_one</code>/<code>find</code> too.</li>
|
||||
<li><strong>Testing (no Mongo):</strong> <code>monkeypatch</code> a fake client on <code>mongo_ops.transactions.MongoConnectionManager.get_client</code> and stub <code>start_session</code> — see <code>tests/test_transactions.py</code>.</li>
|
||||
<li>Repo <strong>models</strong> still carry <code>created_at</code>/<code>updated_at</code>; for raw collection inserts inside the transaction you set them manually (as shown).</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="related">Related</h2>
|
||||
<ul>
|
||||
<li><a href="../03_transactions/">03 – Transactions</a> · <a href="../14_testing_guide/">14 – Testing guide</a> · <a href="../../06_error_handling/">Error Handling</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user