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 5 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
42 changes: 39 additions & 3 deletions source/code-snippets/transactions/txn-core.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
const { MongoError, MongoClient } = require('mongodb');

// drop collections
// Drop the "customers", "inventory", and "orders" collections from the "testdb" database.
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
// Drop the "customers", "inventory", and "orders" collections from the "testdb" database.
// 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 +15,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.
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
// Print all documents in the "customers", "inventory", and "orders" collections.
// 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 +40,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 +73,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,47 +101,68 @@ 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
await session.commitTransaction();
console.log('Transaction successfully committed.');

} catch (error) {
// Handle the UnknownTransactionCommitResult exception
if (error instanceof MongoError && error.hasErrorLabel('UnknownTransactionCommitResult')) {
// add your logic to retry or handle the error
}
// Handle the TransientTransactionError exception
else if (error instanceof MongoError && error.hasErrorLabel('TransientTransactionError')) {
// add your logic to retry or handle the error
// Handle any other exception
} else {
console.log('An error occured in the transaction, performing a data rollback:' + error);
}
// End the transaction without making the updates performed in the session.
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
// End the transaction without making the updates performed in the session.
// End the transaction without making the updates performed in the session

await session.abortTransaction();
} finally {
// End the transaction making all the changes performed in the session.
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
// End the transaction making all the changes performed in the session.
// End the transaction making all the changes performed in the session

await session.endSession();
}
}
// end placeOrder


// Run the full transaction example.
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
// Run the full transaction example.
// 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.
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
// Call a method that removes data from prior runs of this example.
// 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.
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
// Call a method that creates sample inventory data for this example.
// 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.
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
// Create sample data for a customer's shopping cart that includes "sunblock" and "beach towel" items.
// 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.
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
// Create sample data for a customer's payment, calculated from the contents of their cart.
// 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.
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
// Call the method that updates the customer and inventory in a transaction.
// 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.
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
// Call a method that removes data from prior runs of this example.
// 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,70-71,74-75,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