Skip to main content

Your First DB App

Understanding database concepts and how to use them in your applications is knowledge all developers need to acquire. The objective of Your First DB App is to provide a gentle introduction to database concepts and learning one use case for databases in a frontend app.

So, did you know that modern browsers have a database management system built into them? IndexedDB is built into most modern browsers and provides developers with basic database features, transaction support, and client-side cross-session persistance.

Requirements & Constraints

  • The primary use case for a browser based database is to maintain state or status information that needs to persist across sessions, or as a work area for temporary data. For example, data retrieved from a server that must be reformatted or cleansed before it's presented to the user.

  • It is important to keep in mind that since the client-side browser environment cannot be secured you should not maintain any confidential or personal identifying information (PII) in a browser based database.

  • The following Javascript class is provided with the functionality to allow your app to initially populate and clear the database from the browser so you can test the query logic you'll be adding. You'll be required to hook up buttons on the web page you build to the clearDB and loadDB functions, and to write your own queryDB handler to connect to the Query DB button. You'll also need to add a queryAllRows function to the Customer class.

class Customer {
constructor(dbName) {
this.dbName = dbName;
if (!window.indexedDB) {
window.alert(
"Your browser doesn't support a stable version of IndexedDB. \
Such and such feature will not be available."
);
}
}

/**
* Remove all rows from the database
* @memberof Customer
*/
removeAllRows = () => {
const request = indexedDB.open(this.dbName, 1);

request.onerror = (event) => {
console.log(
"removeAllRows - Database error: ",
event.target.error.code,
" - ",
event.target.error.message
);
};

request.onsuccess = (event) => {
console.log("Deleting all customers...");
const db = event.target.result;
const txn = db.transaction("customers", "readwrite");
txn.onerror = (event) => {
console.log(
"removeAllRows - Txn error: ",
event.target.error.code,
" - ",
event.target.error.message
);
};
txn.oncomplete = (event) => {
console.log("All rows removed!");
};
const objectStore = txn.objectStore("customers");
const getAllKeysRequest = objectStore.getAllKeys();
getAllKeysRequest.onsuccess = (event) => {
getAllKeysRequest.result.forEach((key) => {
objectStore.delete(key);
});
};
};
};

/**
* Populate the Customer database with an initial set of customer data
* @param {[object]} customerData Data to add
* @memberof Customer
*/
initialLoad = (customerData) => {
const request = indexedDB.open(this.dbName, 1);

request.onerror = (event) => {
console.log(
"initialLoad - Database error: ",
event.target.error.code,
" - ",
event.target.error.message
);
};

request.onupgradeneeded = (event) => {
console.log("Populating customers...");
const db = event.target.result;
const objectStore = db.createObjectStore("customers", {
keyPath: "userid",
});
objectStore.onerror = (event) => {
console.log(
"initialLoad - objectStore error: ",
event.target.error.code,
" - ",
event.target.error.message
);
};

// Create an index to search customers by name and email
objectStore.createIndex("name", "name", { unique: false });
objectStore.createIndex("email", "email", { unique: true });

// Populate the database with the initial set of rows
customerData.forEach(function (customer) {
objectStore.put(customer);
});
db.close();
};
};
}

// Web page event handlers
const DBNAME = "customer_db";

/**
* Clear all customer data from the database
*/
const clearDB = () => {
console.log("Delete all rows from the Customers database");
let customer = new Customer(DBNAME);
customer.removeAllRows();
};

/**
* Add customer data to the database
*/
const loadDB = () => {
console.log("Load the Customers database");

// Customers to add to initially populate the database with
const customerData = [
{ userid: "444", name: "Bill", email: "[email protected]" },
{ userid: "555", name: "Donna", email: "[email protected]" },
];
let customer = new Customer(DBNAME);
customer.initialLoad(customerData);
};

User Stories

  • User can see a web page containing a control panel containing three buttons - 'Load DB', 'Query DB', and 'Clear DB'.
  • User can see a notification panel where status messages will be posted.
  • User can see a scrollable log panel where execution details describing the apps operation and interface with the Customer instance will be posted.
  • User can see a running history of notification panel messages in the log panel.
  • User can see a scrollable query results area where retrieved customer data will be displayed.
  • User can click the 'Load DB' button to populate the database with data. The 'Load DB' button in your UI should be hooked to the loadDB event handler that's provided.
  • User can see a message displayed in the notification panel when the data load operation starts and ends.
  • User can click the 'Query DB' button to list all customers in the query results area. The 'Query DB' button in your UI should be hooked to a queryDB event handler you will add to the program.
  • User can see a message in the notification panel when the query starts and ends.
  • User can see a message in the query results area if there are no rows to display.
  • User can click on the 'Clear DB' button to remove all rows from the database. The 'Clear DB' button in your UI should be hooked to the clearDB event handler that's provided.
  • User can see a message in the notification panel when the clear operation starts and ends.

Bonus features

  • User can see buttons enabled and disabled according to the following table.

    | State               | Load DB  | Query DB | Clear DB |
    |---------------------|----------|----------|----------|
    | Initial App display | enabled | enabled | disabled |
    | Load DB clicked | disabled | enabled | enabled |
    | Query DB clicked | disabled | enabled | enabled |
    | Clear DB clicked | enabled | enabled | disabled |
  • User can see additional Customer data fields added to those included in the code provided. Developer should add date of last order and total sales for the year.

  • Developer should conduct a retrospection on this project:

    • What use cases can you see for using IndexedDB in your frontend apps?
    • What advantages and disadvantages can you see over using a file or local storage?
    • In general, what criteria might you use to determine if IndexedDB is right for your app. (Hint: 100% yes or no is not a valid answer).

Example projects

  • N/a

Comments