Here are a series of 5 short programming challenges in JavaScript.
Data model
Here is the library data model in an informal way:
More formally, here is a UML diagram that describes the relationships between the data entities of the library:
Here is an example of library data in JavaScript that we are going to use through this article:
var libraryData = {
"name": "The smallest library on earth",
"address": "Here and now",
"catalog": {
"booksByIsbn": {
"978-1779501127": {
"isbn": "978-1779501127",
"title": "Watchmen",
"publicationYear": 1987,
"authorIds": ["alan-moore",
"dave-gibbons"],
"bookItems": [
{
"id": "book-item-1",
"rackId": "rack-17",
},
{
"id": "book-item-2",
"rackId": "rack-17",
}
]
}
},
"authorsById": {
"alan-moore": {
"name": "Alan Moore",
"bookIsbns": ["978-1779501127"]
},
"dave-gibbons": {
"name": "Dave Gibbons",
"bookIsbns": ["978-1779501127"]
}
}
},
"userManagement": {
"librarians": {
"franck@gmail.com" : {
"email": "franck@gmail.com",
"encryptedPassword": "bXlwYXNzd29yZA=="
}
},
"members": {
"samantha@gmail.com": {
"email": "samantha@gmail.com",
"encryptedPassword": "c2VjcmV0",
"isBlocked": false,
}
}
}
};
Warm up
What’s the title of the book whose ISBN is “978-1779501127” in upper case?
I suggest you use Lodash with its FP flavour Lodash FP. Here’s the documentation of the Lodash libray.
Here’s an example:
var informationPath = ["catalog", "booksByIsbn", "978-1779501127", "title"];
_.get(libraryData, informationPath).toUpperCase();
Challenge #1: Retrieve a piece of information
Challenge : Write a function named getBookProperty
that receives library data and ISBN and a field name and returns the value of the field for the book with the given ISBN
function getBookProperty(libraryData, isbn, fieldName) {
// Write your code here using _.get
}
getBookProperty(libraryData, "978-1779501127", "title") === "Watchmen"
Challenge #2: Search information
Challenge : Write a function named bookInfo
that receives library data and a string and returns a JSON string that contains book information about the books whose title contains the given string, in a case insensitive way. Book information is made of: title, isbn, author full names.
Remark: You are not allowed to extract author names from author ids. Assume that author ids are opaque strings.
function searchBooksByTitle(libraryData, query) {
// Write your code here using _.get, _.map and _.filter
}
function searchBooksByTitleJSON(libraryData, query) {
return JSON.stringify(searchBooksByTitle(libraryData, query));
}
var expected = [
{
"authorNames": [
"Alan Moore",
"Dave Gibbons",
],
"isbn": "978-1779501127",
"title": "Watchmen",
},
]
_.isEqual(searchBooksByTitle(libraryData, "watCH"), expected)
Challenge #3: Add a piece of information
Challenge: Write a function named blockMember
that receives library data and an email address and returns a new version of library data without altering the original version, where the user with the given email is blocked.
Remember that we are using a version of Lodash that, instead of mutating data in place, creates a new version.
function blockMember(libraryData, email) {
// Write your code here using _.set
}
var updatedLibraryData = blockMember(libraryData, "samantha@gmail.com");
var informationPath = ["userManagement", "members", "samantha@gmail.com", "isBlocked"];
_.get(updatedLibraryData, informationPath) == true
_.get(libraryData, informationPath) === false
In Data-Oriented programming, data is immutable. Functions like _.set()_
make it efficient (both in terms of memory and computation) to create modified versions of data.
Challenge #4: Rename keys in a data entity
Challenge: Write a function named renameKeys
that receives a data entity and a key mappings and returns a new data entity, without altering the original entity, where the fields are renamed according to the key mappings
function renameKeys(map, keyMap) {
// Write your code here using _.get, _.set, _.omit and _.reduce
}
renameKeys
works with author entities:
var alanMoore = {
"name": "Alan Moore",
"bookIsbns": ["978-1779501127"]
};
var expected = {
"name": "Alan Moore",
"books": [
"978-1779501127",
],
}
_.isEqual(renameKeys(alanMoore, {"bookIsbns": "books"}), expected)
renameKeys
should also works also with book item entities:
var bookItem = {
"id": "book-item-1",
"rackId": "rack-17",
"isLent": true
};
var expected = {
"bookItemId": "book-item-1",
"isLent": true,
};
_.isEqual(
renameKeys(bookItem, {"rackId": "id",
"id": "bookItemId"}),
expected)
In Data-Oriented programming, data entities are represented with generic data structures that can be manipulated with generic functions that work with any data entity.
Challenge #5: Merge pieces of information
Challenge: Write a function named mergeAndSerialize
that receives two pieces of book information, one from the database and one from an external service like Open Library Books API and returns a JSON string with information from both sources.
var watchmenFromDB = {
"isbn": "978-1779501127",
"title": "Watchmen",
"publicationYear": 1987,
"authorIds": ["alan-moore",
"dave-gibbons"],
"bookItems": [
{
"id": "book-item-1",
"rackId": "rack-17",
"isLent": true
},
{
"id": "book-item-2",
"rackId": "rack-17",
"isLent": false
}
]
};
var watchmenFromOpenLib = {
"publishers": [
"DC Comics"
],
"number_of_pages": 334,
"weight": "1.4 pounds",
"physical_format": "Paperback",
"subjects": [
"Graphic Novels",
"Comics & Graphic Novels",
"Fiction",
"Fantastic fiction"
],
"isbn_13": [
"9780930289232"
],
"title": "Watchmen",
"isbn_10": [
"0930289234"
],
"publish_date": "April 1, 1995",
"physical_dimensions": "10.1 x 6.6 x 0.8 inches"
}
function mergeAndSerialize(a, b) {
// Write your code here using _.merge
}
mergeAndSerialize(watchmenFromDB, watchmenFromOpenLib);
When we represent data with generic data structures, we benefit from many well defined functions like merge
, implemented either in the programming language itself or in third-party libraries like `Lodash.js.