To implement this assignment, I used node.js, alongside a few other npm packages, for parsing the CSV file. Since no external database was required/allowed, I loaded all the data to the main memory, using Map and a Prefix Trie as my data structures, in order to get the best asymptotic runtime for the required API.
I used JS Map with id/country as keys.
I used JS Map with the year, month and day of the user's dob as keys. Also, I used the javascript date object to determine the required dates for the age we are looking for from the GET request.
I used JS Map with full names and first/last names as keys. Also, I used trie to add the first/last names prefixes, so we can know which keys to retrieve from the userMapByName.
I retrieve all the relevant user information (name, country, dob) from the userMapByID, which were used as keys in the data structures, and then removed all other references.
In each iteration, we parse a single user from the CSV data file and add it to the Maps and Trie Data Structures. Adding a (key, value) entry to the Map’s data structures should take O(1)
. Adding a name to the Trie should take O(Length of First/Last name)
, but we can assume that the length of a first/last name is blocked by some constant size so it should take O(1)
as well. Overall, we get that the initialization runtime is O(N)
where N
is the number of users.
Getting and retrieving the user from usersMapById by the given id from the GET request – O(1)
Getting a reference to all the users living in a specific country by using usersMapByCountry – O(1)
Returning All users living in a specific country – O(Ncountry)
, where Ncountry
is the number of users living in the given country from the GET request.
Getting a reference to all the users of the given age by using usersMapbyAge – O(1)
Returning All users of the specific age – O(Nage)
,
Where Nage
is the number of users of that specific given age from the GET request.
Getting a reference to all the users of a specific full name or full single/last name by using userNameMap – O(1)
.
Returning All users of that specific name – O(Nname)
, Where Nname
is the number of users that have that specific name, either full name or as first/last name.
If nothing was found, then we’ll move to match partial name, as follow:
Retrieving all names of given prefix – O(M+Nprefix)
, where M
is the maximum length of a first/last name, and N
is the number of first/last names that start with that given prefix from the GET request. We can assume that the length of a first/last name is upper bound by some constant therefore we receive O(Nprefix)
.
We now found all single/last names that match the prefix and we need to extract them from usersMapByName.
since we can get a reference to all the users of a specific full name or full single/last name by O(1)
, as mentioned above, Retrieving all users which their first/last name matches the prefix will take O(NallMatchedUser)
, where NallMatchedUser
is the number of users which their first/last name match the prefix.
deleting from Maps should take O(1)
.
deleting from trie will occur only if there aren't any other users with the first or last name of the user that about to be deleted. deleting should take O(M)
, where M
is the maximum length of a first/last name in the data. We can assume that the length of a first/last name is upper bound by some constant therefore we receive O(1)
.
Looking at the Initialization data runtime complexity, we can infer that the total space required for the data is O(N*SizeOfUserObject)
.
We are using Maps and a Trie to store references to the user. Since those data structures uses some of the user’s data as keys (id, name, country, dob), and since we save only a few references to the same object, the total amount of data required to store those keys is still blocked by the size of O(SizeOfUserObject)
, therefore the total amount of memory that is required is still O(N*SizeOfUserObject)
.
Get user by Id - GET /users/a2ee2667-c2dd-52a7-b9d8-1f31c3ca4eae - Should return the requested user details
Get users list by country - GET /users?country=US - Should return a list of all users from requested country
Get users list by age - GET /users?age=30 - Should return all users which are of age 30 at the time of the request
Get users list by name - GET /users?name=Susan - Should return all users which name matches the requested name - Matching names rules: - Full match - for input "Susan James" should return all users with name "Susan James". - Full first name or last name - for input "Susan" should return all users with that first or last name. - Partial match (minimum 3 chars) - for input "Sus", should return all users with first or last name that begin with "Sus". - Should support non case sensitive search (Searching for "susan" should return users with name "Susan").
Delete user by id - DELETE /users/a2ee2667-c2dd-52a7-b9d8-1f31c3ca4eae - Should delete the user, after the call the user will not be returned by any of the previous APIs.
npm install
npm start
OR node index.js