Skip to content

DOCSP-32718: add CodeWhisperer comments to transactions code snippets #769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Sep 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 41 additions & 3 deletions source/code-snippets/transactions/txn-core.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
/* Performs multiple write operations in a transaction */

const { MongoError, MongoClient } = require('mongodb');

// drop collections
// Drop the "customers", "inventory", and "orders" collections from the "testdb" database
async function cleanUp(client) {
await Promise.all( ['customers', 'inventory', 'orders'].map(async c => {
try {
const coll = client.db('testdb').collection(c);
await coll.drop();
} catch(e) {}
} catch(e) {} // Ignore any exceptions
}));
}

Expand All @@ -15,17 +17,21 @@ async function setup(client) {
const customerColl = client.db('testdb').collection('customers');
const inventoryColl = client.db('testdb').collection('inventory');

// Insert order data for customer "98765" in the customers collection
await customerColl.insertOne({ _id: 98765, orders: [] });

// Insert inventory data for "sunblock" and "beach towel"
await inventoryColl.insertMany([
{ name: 'sunblock', sku: 5432, qty: 85 },
{ name: 'beach towel', sku: 7865, qty: 41 },
]);
} catch (e) {
// Print the exception if one was thrown
console.log('Unable to insert test data: ' + e);
}
}

// Print all documents in the "customers", "inventory", and "orders" collections
async function queryData() {
const uri = process.env.MONGODB_URI;
const client = new MongoClient(uri);
Expand All @@ -36,23 +42,29 @@ async function queryData() {
}, client));

} finally {
// Close the database connection
client.close();
}
}

// start placeOrder
async function placeOrder(client, cart, payment) {
// Specify readConcern, writeConcern, and readPreference transaction options
const transactionOptions = {
readConcern: { level: 'snapshot' },
writeConcern: { w: 'majority' },
readPreference: 'primary'
};

// Start the session
const session = client.startSession();
try {
// Start the transaction in the session, specifying the transaction options
session.startTransaction(transactionOptions);

const ordersCollection = client.db('testdb').collection('orders');
// Within the session, insert an order that contains information about the
// customer, items purchased, and the total payment.
const orderResult = await ordersCollection.insertOne(
{
customer: payment.customer,
Expand All @@ -63,21 +75,26 @@ async function placeOrder(client, cart, payment) {
);

const inventoryCollection = client.db('testdb').collection('inventory');

// Within the session, for each item purchased, decrement the purchased quantity in the "inventory" collection.
// Cancel the transaction when you have insufficient inventory or if the item SKU does not exist.
for (let i=0; i<cart.length; i++) {
const item = cart[i];

// Cancel the transaction when you have insufficient inventory
// Retrieve the inventory information for the item
const checkInventory = await inventoryCollection.findOne(
{
sku: item.sku,
qty: { $gte: item.qty }
},
{ session }
)
// Throw an exception if the item lacks sufficient quantity or SKU does not exist.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Throw an exception if the item lacks sufficient quantity or SKU does not exist.
// Throw an exception if the item lacks sufficient quantity or SKU does not exist

if (checkInventory === null) {
throw new Error('Insufficient quantity or SKU not found.');
}

// Decrement the inventory of the item by the amount specified in the order.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Decrement the inventory of the item by the amount specified in the order.
// Decrement the inventory of the item by the amount specified in the order

await inventoryCollection.updateOne(
{ sku: item.sku },
{ $inc: { 'qty': -item.qty }},
Expand All @@ -86,15 +103,23 @@ async function placeOrder(client, cart, payment) {
}

const customerCollection = client.db('testdb').collection('customers');

// Within the session, add the order details to the "orders" array of the customer document.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Within the session, add the order details to the "orders" array of the customer document.
// Within the session, add the order details to the "orders" array of the customer document

await customerCollection.updateOne(
{ _id: payment.customer },
{ $push: { orders: orderResult.insertedId }},
{ session }
);

// Commit the transaction to apply all updates performed within it
await session.commitTransaction();
console.log('Transaction successfully committed.');

} catch (error) {
/*
Handle any exceptions thrown during the transaction and end the
transaction. Roll back all the updates performed in the transaction.
*/
if (error instanceof MongoError && error.hasErrorLabel('UnknownTransactionCommitResult')) {
// add your logic to retry or handle the error
}
Expand All @@ -105,28 +130,41 @@ async function placeOrder(client, cart, payment) {
}
await session.abortTransaction();
} finally {
// End the session so that no further calls can be made on it
await session.endSession();
}
}
// end placeOrder


// Run the full transaction example
async function run() {
const uri = process.env.MONGODB_URI;
const client = new MongoClient(uri);

// Call a method that removes data from prior runs of this example
await cleanUp(client);

// Call a method that creates sample inventory data for this example
await setup(client);

// Create sample data for a customer's shopping cart that includes "sunblock" and "beach towel" items
const cart = [
{ name: 'sunblock', sku: 5432, qty: 1, price: 5.19 },
{ name: 'beach towel', sku: 7865, qty: 2, price: 15.99 }
];

// Create sample data for a customer's payment, calculated from the contents of their cart
const payment = { customer: 98765, total: 37.17 };

try {
// Call the method that updates the customer and inventory in a transaction
await placeOrder(client, cart, payment);
} finally {
// Call a method that removes data from prior runs of this example
await cleanUp(client);

// Close the database connection
await client.close();
}
}
Expand Down
10 changes: 5 additions & 5 deletions source/fundamentals/transactions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Overview
In this guide, you can learn how to use the
{+driver-short+} to perform **transactions**. Transactions allow you
to run a series of operations that do not change any data until the
entire transaction is committed. If any operation in the transaction fails, the
entire transaction is committed. If any operation in the transaction fails, the
driver aborts the transaction and discards all data changes before they
ever become visible. This feature is called **atomicity**.

Expand Down Expand Up @@ -247,16 +247,16 @@ shows how you can perform the following:
.. literalinclude:: /code-snippets/transactions/txn-core.js
:language: javascript
:linenos:
:emphasize-lines: 2-6,8,10,19,32,41,49,51,55-59,63,65
:emphasize-lines: 3-7,13,24,40,51,61,65,73-74,76-77,81,84
:start-after: start placeOrder
:end-before: end placeOrder

You must pass the session object to each CRUD operation that
you want to run on that session.

.. important:: Use a Session with the Client That Started It
Starting in version 6.0 of the {+driver-short+}, the driver

Starting in version 6.0 of the {+driver-short+}, the driver
throws an error if you provide a session from one ``MongoClient``
instance to a different client instance.

Expand All @@ -267,7 +267,7 @@ you want to run on that session.

.. code-block:: js
:emphasize-lines: 2

const session = client1.startSession();
client2.db('myDB').collection('myColl').insertOne({ name: 'Jane Eyre' }, { session });

Expand Down