diff --git a/Projects/First-DB-App.md b/Projects/First-DB-App.md new file mode 100644 index 00000000..2dff920a --- /dev/null +++ b/Projects/First-DB-App.md @@ -0,0 +1,200 @@ +# Your First DB App + +**Tier:** 1-Beginner + +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: 'bill@company.com' }, + { userid: '555', name: 'Donna', email: 'donna@home.org' } + ]; + 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). + + +## Useful links and resources + +- [IndexedDB Concepts (MDN)](http://tinyw.in/7TIr) +- [Using IndexedDB (MDN)](http://tinyw.in/w6k0) +- [IndexedDB API (MDN)](http://tinyw.in/GqnF) +- [IndexedDB Browser Support](https://caniuse.com/#feat=indexeddb) + +## Example projects + +- N/a diff --git a/README.md b/README.md index 32dc6cea..0422c175 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ required to complete them. | [🌟Countdown Timer](./Projects/Countdown-Timer-App.md) | Event Countdown timer | 1-Beginner | | [CSV2JSON App](./Projects/CSV2JSON-App.md) | CSV to JSON converter | 1-Beginner | | [🌟Dynamic CSS Variables](./Projects/Dynamic-CSSVar-app.md) | Dynamically change CSS variable settings | 1-Beginner | +| [🌟First DB App](./Projects/First-DB-App.md) | Your first Database app! | 1-Beginner | | [Flip Image](./Projects/Flip-Image-App.md) | Change the orientation of images across two axes | 1-Beginner | | [🌟GitHub Status](./Projects/GitHub-Status-App.md) | Display Current GitHub Status | 1-Beginner | | [🌟Hello](./Projects/Hello-App.md) | User native language greeting | 1-Beginner |