diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..a3159ab --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,29 @@ +{ + "env": { + "browser": true, + "es6": true, + "mocha": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "indent": [ + "error", + 2 + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "double" + ], + "semi": [ + "error", + "always" + ] + } +} diff --git a/Classes/passenger.js b/Classes/passenger.js new file mode 100644 index 0000000..e69de29 diff --git a/Classes/station.js b/Classes/station.js new file mode 100644 index 0000000..6d08815 --- /dev/null +++ b/Classes/station.js @@ -0,0 +1,122 @@ +const trainQueries = require('../Database/Queries/trains.queries'); +const passengerQueries = require('../Database/Queries/passengers.queries'); +const genericQueries = require('../Database/Queries/generic.queries'); +const stationQueries = require('../Database/Queries/stations.queries'); + +module.exports = class Station { + constructor(stationName = "", id = undefined, order = undefined) { + this.id = id; + this.stationName = stationName; + this.order = order; + } + + getId() { + return this.id; + } + + getStationName() { + return this.stationName; + } + + getWaitingPassengers(callback) { + passengerQueries.findPassengersByStation(this.stationName) + .then(data => { + callback(data); + }) + .catch(error => { + console.log('An error occured', error); + }); + } + + getPassengersWithTickets(callback) { + passengerQueries.findPassengersByStation(this.stationName) + .then(data => { + let filteredData = data.filter(element => { + return element.has_ticket; + }); + callback(filteredData); + }) + .catch(error => { + console.log('An error occured', error); + }); + } + + getPreviousStation(callback) { + let preOrder = this.order - 1; + if (preOrder === 0) { + stationQueries.getCountOfStations() + .then(number => { + preOrder = number[0].count; + return preOrder; + }) + .then(order => { + return stationQueries.findStationByOrder(order); + }) + .then(station => { + callback(station); + }); + } + else { + stationQueries.findStationByOrder(preOrder) + .then(station => { + callback(station); + }) + } + } + + getNextStation(callback) { + let nextOrder = this.order + 1; + stationQueries.getCountOfStations() + .then(count => { + if(nextOrder > count) { + nextOrder = 1; + } + stationQueries.findStationByOrder(nextOrder) + .then(station => { + callback(station); + }); + }) + } + + static getNextTrainOf( name, callback ) { + stationQueries.findStationByName(name) + .then(station => { + let preOrder = station[0].order - 1; + if ( preOrder === 0 ) { + stationQueries.getCountOfStations() + .then(count => { + preOrder = count[0].count; + return preOrder; + }) + .then(order => { + return stationQueries.findStationByOrder(order); + }) + .then(station => { + return trainQueries.findTrainsAtStation(station[0].id); + }) + .then(trains => { + callback(trains); + }) + } + else { + stationQueries.findStationByOrder(preOrder) + .then( station => { + return trainQueries.findTrainsAtStation(station[0].id); + }) + .then( trains => { + callback(trains); + }) + } + }) + } + + // this finds a station by ID and makes it persist + loadInstanceOfStationById(id = this.id) { + return stationQueries.findStationById(id) + .then(station => { + this.stationName = station[0].station_name; + this.order = station[0].order; + this.id = station[0].id; + }) + } +} diff --git a/Classes/train.js b/Classes/train.js new file mode 100644 index 0000000..8f7dfb0 --- /dev/null +++ b/Classes/train.js @@ -0,0 +1,133 @@ +const trainQueries = require('../Database/Queries/trains.queries'); +const passengerQueries = require('../Database/Queries/passengers.queries'); +const genericQueries = require('../Database/Queries/generic.queries'); +const stationQueries = require('../Database/Queries/stations.queries'); + +module.exports = class Train { + constructor(id = undefined, number = undefined, capacity = undefined) { + this.id = id; + this.number = number; + this.numberOfPassengers = undefined; + this.capacity = capacity; + this.currentStationId = undefined; + } + + getNumber() { + return this.number; + } + + getCapacity() { + return this.capacity; + } + + getPassengers() { + return passengerQueries.findPassengersByTrain(this.id) + .catch(error => { + console.log('An error occured:', error); + }) + } + + isFull() { + return this.capacity === this.numberOfPassengers; + } + + getCurrentStation() { + return stationQueries.findStationById(this.currentStationId) + .then(station => { + return station[0]; + }) + .catch(error => { + console.log('An error occured:', error); + }); + } + + getNextStation() { + return Promise.all([ + stationQueries.findStationById( this.currentStationId ), + stationQueries.getCountOfStations() + ]) + .then( ([ station, count ]) => { + // return (( station[ 0 ].order + 1 ) % ( station[ 0 ].order + 1 )) || 1; + if ((station[0].order + 1) > count[0].count) { + return 1; + } + else return station[0].order + 1; + }) + .then( stationQueries.findStationByOrder ) + .then( nextStation => nextStation[ 0 ] ) + .catch( error => console.log( 'An error occurred', error )) + } + + moveTrain() { + return this.getNextStation() + .then(station => { + this.currentStationId = station.id; + return station; + }) + } + + offBoard() { + return passengerQueries.findDesAndTrainId(this.currentStationId, this.id) + .then(passengers => { + let promises = []; + passengers.forEach(passenger => { + passenger.destination_id = null; + passenger.current_station_id = this.currentStationId; + passenger.current_train_id = null; + passenger.has_ticket = false; + promises.push(genericQueries.update("passengers", passenger)); + }) + return Promise.all(promises); + }) + .catch(error => { + console.log('An error occurred: ', error); + }) + } + + onBoard() { + return passengerQueries.findByStationIdAndTicket(this.currentStationId) + .then(passengers => { + let promises = []; + passengers.forEach(passenger => { + passenger.current_station_id = null; + passenger.current_train_id = this.id; + promises.push(genericQueries.update("passengers", passenger)); + }) + return Promise.all(promises); + }) + } + + loadInstanceOfTrainById(id = this.id) { + return trainQueries.findTrainById(id) + .then(train => { + this.id = train[0].id; + this.number = train[0].number; + this.numberOfPassengers = train[0].number_of_passengers; + this.capacity = train[0].capacity; + this.currentStationId = train[0].current_station_id; + return this; + }) + .catch(error => { + console.log(error); + }); + } + + loadInstanceOfTrainByNum(number = this.number) { + return trainQueries.findTrainByNumber(number) + .then(train => { + if (train.length > 1) { + console.log('There are more than one trains with this number. We are loading the first instance of the train.'); + } + this.id = train[0].id; + this.number = train[0].number; + this.numberOfPassengers = train[0].number_of_passengers; + this.capacity = train[0].capacity; + this.currentStationId = train[0].current_station_id; + return this; + }) + .catch(error => { + console.log(error); + }); + } + +} diff --git a/Database/Queries/generic.queries.js b/Database/Queries/generic.queries.js new file mode 100644 index 0000000..75d3f86 --- /dev/null +++ b/Database/Queries/generic.queries.js @@ -0,0 +1,26 @@ +const db = require("../database.js"); + +const save = (table, object) => { + return db(table) + .returning("id") + .insert(object) +} + +const update = (table, object) => { + return db(table) + .returning("id") + .where("id", "=", object.id) + .update(object) +} + +const del = (table, id) => { + return db(table) + .where("id", "=", id) + .del(); +} + +module.exports = { + save: save, + update: update, + del: del +}; diff --git a/Database/Queries/passengers.queries.js b/Database/Queries/passengers.queries.js new file mode 100644 index 0000000..ff14f92 --- /dev/null +++ b/Database/Queries/passengers.queries.js @@ -0,0 +1,50 @@ +const db = require("../database.js"); + +const findPassengersByName = (name) => { + return db("passengers") + .where("name", name); +}; + +const findPassengersByStation = (stationName) => { + return db("passengers") + .join("stations", "passengers.current_station_id", "=", "stations.id") + .select("passengers.id", "passengers.name", "passengers.destination_id", + "passengers.has_ticket", "passengers.current_train_id", + "passengers.current_station_id") + .where("stations.station_name", stationName); +}; + +const findByStationIdAndTicket = (stationId) => { + return db("passengers") + .where({ + current_station_id: stationId, + has_ticket: true + }) +}; +const findPassengersByTrain = (trainId) => { + return db("passengers") + .where("current_train_id", trainId); +}; + +const findPassengerById = (passengerId) => { + return db("passengers") + .where("id", passengerId) + .first(); +}; + +const findDesAndTrainId = (destinationId, trainId) => { + return db("passengers") + .where({ + destination_id: destinationId, + current_train_id: trainId + }) +}; + +module.exports = { + findPassengersByName: findPassengersByName, + findPassengersByStation: findPassengersByStation, + findPassengersByTrain: findPassengersByTrain, + findPassengerById: findPassengerById, + findDesAndTrainId: findDesAndTrainId, + findByStationIdAndTicket: findByStationIdAndTicket +}; diff --git a/Database/Queries/stations.queries.js b/Database/Queries/stations.queries.js new file mode 100644 index 0000000..141e8db --- /dev/null +++ b/Database/Queries/stations.queries.js @@ -0,0 +1,31 @@ +const db = require("../database.js"); + +const findStationById = (id) => { + return db("stations") + .select() + .where("id", "=", id); +}; + +const findStationByOrder = (order) => { + return db("stations") + .select() + .where("order", "=", order); +}; + +const findStationByName = (name) => { + return db("stations") + .select() + .where("station_name", "=", name); +}; + +const getCountOfStations = () => { + return db("stations").count(); +} + + +module.exports = { + findStationById: findStationById, + findStationByOrder: findStationByOrder, + findStationByName: findStationByName, + getCountOfStations: getCountOfStations +}; diff --git a/Database/Queries/trains.queries.js b/Database/Queries/trains.queries.js new file mode 100644 index 0000000..7290817 --- /dev/null +++ b/Database/Queries/trains.queries.js @@ -0,0 +1,25 @@ +const db = require("../database.js"); + +const findTrainByNumber = (number) => { + return db("trains") + .select() + .where("number", "=", number); +}; + +const findTrainById = (id) => { + return db("trains") + .select() + .where("id", "=", id); +}; + +const findTrainsAtStation = (stationId) => { + return db("trains") + .select() + .where("current_station_id", "=", stationId); +}; + +module.exports = { + findTrainByNumber: findTrainByNumber, + findTrainById: findTrainById, + findTrainsAtStation: findTrainsAtStation +}; diff --git a/Database/Seeds/seed.js b/Database/Seeds/seed.js new file mode 100644 index 0000000..ddb13d7 --- /dev/null +++ b/Database/Seeds/seed.js @@ -0,0 +1,101 @@ +const db = require('../database'); + +const trainData = [ + { + number: 1, + capacity: 55, + number_of_passengers: 0 + }, + { + number: 2, + capacity: 120, + number_of_passengers: 0 + }, + { + number: 3, + capacity: 23, + number_of_passengers: 0 + }, + { + number: 4, + capacity: 70, + number_of_passengers: 0 + } +]; + +const stationData = [ + { + station_name: "Downtown" + }, + { + station_name: "Elm Street" + }, + { + station_name: "Forest Gardens" + }, + { + station_name: "Annex" + }, + { + station_name: "10th Ave" + }, + { + station_name: "Waterfront" + }, + { + station_name: "Colosseum" + }, + { + station_name: "Central Station" + }, + { + station_name: "Parkside" + }, + { + station_name: "Grand Boulevard" + }, + { + station_name: "Monument Valley" + }, + { + station_name: "Museum Isle" + } +]; + +const passengerData = [ + { + name: "John Dope", + has_ticket: false + }, + { + name: "Sabrina Smith", + has_ticket: false + }, + { + name: "Anish Sadhaji", + has_ticket: false + }, + { + name: "Pooh Bear", + has_ticket: false + } +]; + +exports.seed = (knex, promise) => { + let promises = []; + stationData.forEach(data => { + promises.push(insertData(knex, data, "stations")); + }); + trainData.forEach(data => { + promises.push(insertData(knex, data, "trains")); + }); + passengerData.forEach(data => { + promises.push(insertData(knex, data, "passengers")); + }); + return Promise.all(promises); +} + +function insertData(knex, data, table) { + return knex.insert(data) + .into(table); +} diff --git a/Database/database.js b/Database/database.js new file mode 100644 index 0000000..e6e0725 --- /dev/null +++ b/Database/database.js @@ -0,0 +1,6 @@ +const config = require('../knexfile'); +let env = process.env.NODE_ENV || 'development'; + +let knex = require('knex')(config[env]); + +module.exports = knex; diff --git a/Test/passenger.test.js b/Test/passenger.test.js new file mode 100644 index 0000000..e69de29 diff --git a/Test/station.test.js b/Test/station.test.js new file mode 100644 index 0000000..e69de29 diff --git a/Test/train.test.js b/Test/train.test.js new file mode 100644 index 0000000..e69de29 diff --git a/app.js b/app.js new file mode 100644 index 0000000..6e26644 --- /dev/null +++ b/app.js @@ -0,0 +1,10 @@ +const Station = require('./Classes/station'); +const Train = require('./Classes/train') +const db = require('./Database/database'); + +// User: add code here + + +setTimeout( () => { + db.destroy(); +}, 2000); diff --git a/knexfile.js b/knexfile.js new file mode 100644 index 0000000..e057722 --- /dev/null +++ b/knexfile.js @@ -0,0 +1,11 @@ +module.exports = { + development: { + client: 'postgresql', + connection: { + database: 'metrorail_dev' + }, + seeds: { + directory: './Database/Seeds' + } + } +}; diff --git a/migrations/20170502130947_metrorail.js b/migrations/20170502130947_metrorail.js new file mode 100644 index 0000000..596635d --- /dev/null +++ b/migrations/20170502130947_metrorail.js @@ -0,0 +1,48 @@ + +exports.up = function(knex, Promise) { + + return Promise.all([ + + knex.schema.createTable('trains', function(table) { + table.increments('id').primary(); + table.integer('number'); + table.integer('capacity'); + table.integer('number_of_passengers'); + table.integer('current_station_id') + .references('id') + .inTable('stations'); + }), + + knex.schema.createTable('stations', function(table){ + table.increments('id').primary(); + table.string('station_name'); + }), + + knex.raw('alter table "stations" add column "order" serial'), + + knex.schema.createTable('passengers', function(table){ + table.increments('id').primary(); + table.string('name'); + table.integer('destination_id'); + table.boolean('has_ticket'); + table.integer('current_train_id') + .references('id') + .inTable('trains'); + table.integer('current_station_id') + .references('id') + .inTable('stations'); + }) + ]) + +}; + +exports.down = function(knex, Promise) { + + return Promise.all([ + + knex.schema.dropTable('trains'), + knex.schema.dropTable('stations'), + knex.schema.dropTable('passengers') + + ]) +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..71db764 --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "name": "metrorail", + "version": "1.0.0", + "description": "Create a database API for a model train system", + "main": "app.js", + "scripts": { + "start": "node app.js", + "test": "echo \"Error: no test specified\" && exit 1", + "repl": "echo 'this entered here'", + "linter": "node_modules/.bin/eslint .", + "db:create": "createdb metrorail_dev", + "db:migrate": "node_modules/.bin/knex migrate:latest", + "db:seed": "node_modules/.bin/knex seed:run", + "db:drop": "dropdb metrorail_dev", + "db:reset": "dropdb metrorail_dev && createdb metrorail_dev && node_modules/.bin/knex migrate:latest", + "db:console": "psql metrorail_dev" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/zubairnahmed/metrorail.git" + }, + "author": "Zubair and Jose", + "license": "MIT", + "bugs": { + "url": "https://github.com/zubairnahmed/metrorail/issues" + }, + "homepage": "https://github.com/zubairnahmed/metrorail#readme", + "devDependencies": { + "eslint": "^3.19.0" + }, + "dependencies": { + "express": "^4.15.2", + "knex": "^0.13.0", + "pg": "^6.1.5" + } +}