CircleCI

Availability Service

This module consists of a class that has one main method, checkAvailability(). This method accepts a start date and an end date as strings formatted like 'YYYY-MM-DD', along with an array of reservation objects, formatted like:

{"campsiteId": 1, "startDate": "2016-06-01", "endDate": "2016-06-04"}

The method will check to see which sites, identified by 'campsiteId', have openings for the requested dates, taking the gap rules into consideration.

Gap Rules

To eliminate or minimize un-booked sites, site owners utilize "Gap Rules" which enforce a maximum number of days unbooked between reservations. To illustrate, consider a site that has existing reservations spanning the 1st through the 3rd of the month and the 10th through the 15th. If a gap rule exists that states the maximum gap is 2 days, a request for a reservation spanning the 4th through the 7th would be denied, because the gap between the 7th and the 10th violates the rule.

High-Level Approach

My approach for this challenge centered around implementing the solution in a manner that allowed easy reuse and high cohesion. I chose to create a module that would implement the functionality in either a server environment or in the browser. To accomplish this, I wrote the module as an ES2015 module, and then transpiled it using Babel and the babel-plugin-add-module-exports plugin to allow it to be used with require() or import.

To support a more effective workflow, I set up a CI workflow using CircleCI which automatically builds the module and runs the tests each time a commit is pushed to master. The badge at the top of this page illustrates the current build status. This process could be improved by enforcing a rule that the CI build must pass successfully before commits are allowed to be merged into the master branch.

To make it easier for other applications to use this module as a dependency, I've published it on npm. This makes it easy for other applications to easily include it using npm install availability-service and to require that specific versions be used. Details of the example API are provided below.

The processing of the reservation list to determine availability follows four main steps:

  1. Remove any reservation objects that contain a reservation which overlaps the requested date range
  2. Remove all reservation objects that relate to a site that has an overlapping reservation (in a different reservation object)
  3. Parse the remaining reservations into a format like:

    { 
      campsiteId: 1, 
      reservations: [ 
        [startDate1, endDate1], 
        [startDate2, endDate2], 
        [startDate3, endDate3] 
      ] 
    }
    
  4. Calculate the gap between each reservation in the reservations array above, and calculate if the requested range will fit without violating the gap rules.

Assumptions

When determining how to solve this problem, I made the following assumptions:

  1. The gap rule value was to be used in an inclusive comparison. In other words, if the gap rule is 2, that means that the difference between the end of one reservation and the beginning of another must be less than or equal to 2, rather than less than 2.
  2. If there's more than one gap rule, the smallest rule takes precedence.
  3. The gap rules before and after the requested range must be calculated.
  4. If there's no reservation before a requested range or there's not one after it, there's no need to calculate the gap rule for that span.

Dependencies

To speed development time, I used the popular moment.js library to extend the Date object, and the moment-range library to provide additional methods for calculating date ranges.

Building and Running Tests

Example Implementation

To provide an example implementation, I created a Loopback API that exposes a route, /reservations/availability. This route is available for POST requests only, and requires two params: startDate and endDate. It returns a JSON collection of campsite objects that have availability for that date range.

To run the api, simply follow these steps:

  1. Clone or download a copy of campspot-api
  2. Edit ./server/datasources.json and enter your credentials for a MySQL database and a database that you'd like to use for testing
  3. Run npm install to install the dependencies (including this one, availability-service)
  4. Run node . to start the server in a terminal session. This will create a database migration with the data from the provided JSON document (located in the file ./server/boot/test-case.js)
  5. Navigate to http://localhost:3000/explorer/#!/Reservation/Reservation_availability and enter the dates '2016-06-07' and '2016-06-10' in the provided text input fields, then submit.
  6. Inspect the response body. You should see the following JSON object:

    {
      "startDate": "2016-06-07",
      "endDate": "2016-06-10",
      "available_sites": [
        { "name": "Daniel Boone Bungalow", "id": 5 },
        { "name": "Teddy Rosevelt Tent Site", "id": 6 },
        { "name": "Bear Grylls Cozy Cave", "id": 8 },
        { "name": "Wyatt Earp Corral", "id": 9 }
      ]
    }
    

Conclusion

Thank you again for the opportunity. Please feel free to contact me if you have any additional questions or comments.