├── README.md
├── bubble-stack_postgres_create.sql
├── server
├── controllers
│ ├── stackConCopy.js
│ └── stackControllers.js
├── models
│ └── stackModels.js
├── server.js
└── routes
│ └── api.js
├── .gitignore
├── client
├── variables.scss
├── .DS_Store
├── index.tsx
├── index.html
├── components
│ ├── data.ts
│ ├── App.tsx
│ ├── containers
│ │ ├── staticContainer.tsx
│ │ └── mainContainer.tsx
│ ├── map.js
│ ├── Bubble.tsx
│ └── MakeMap.js
└── style.scss
├── .vscode
└── settings.json
├── .DS_Store
├── tsconfig.json
├── webpack.config.js
└── package.json
/README.md:
--------------------------------------------------------------------------------
1 | # Scratch
--------------------------------------------------------------------------------
/bubble-stack_postgres_create.sql:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server/controllers/stackConCopy.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | .vscode
3 | .env
--------------------------------------------------------------------------------
/client/variables.scss:
--------------------------------------------------------------------------------
1 | $primary: rgb(70, 87, 78);
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "eslint.enable": false
3 | }
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Star-Nosed-Mole/Bubble-Stack/HEAD/.DS_Store
--------------------------------------------------------------------------------
/client/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Star-Nosed-Mole/Bubble-Stack/HEAD/client/.DS_Store
--------------------------------------------------------------------------------
/client/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from 'react-dom';
3 | import App from './components/App';
4 |
5 | const style = require('./style.scss');
6 | render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
11 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "sourceMap": true,
6 | "noImplicitAny": false,
7 | "jsx" :"react",
8 | "esModuleInterop": true,
9 | },
10 | "exclude": [
11 | "node_modules"
12 | ]
13 | }
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Document
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/client/components/data.ts:
--------------------------------------------------------------------------------
1 | const testData = {
2 | name: 'nivo',
3 | color: 'hsl(0, 100%, 50%)',
4 | children: [
5 | {
6 | name: 'React',
7 | color: 'hsl(191, 70%, 50%)',
8 | loc: 13285
9 | },
10 | {
11 | name: 'Redux',
12 | color: 'hsl(191, 70%, 50%)',
13 | loc: 13285
14 | }
15 | ]
16 | };
17 |
18 | export default testData;
19 |
--------------------------------------------------------------------------------
/client/components/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import MainContainer from './containers/mainContainer';
3 |
4 | // import MainContainer from './containers/MainContainer';
5 | class App extends Component {
6 | constructor(props) {
7 | super(props);
8 | }
9 | render() {
10 | return (
11 |
12 |
13 |
14 | );
15 | }
16 | }
17 | export default App;
18 |
--------------------------------------------------------------------------------
/client/components/containers/staticContainer.tsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | import Map from '../map';
4 |
5 | // need the div classname because the Map componenet needs to be nested in a div that has height stlying for nivo bubble to work
6 | class StaticContainer extends Component {
7 | constructor(props) {
8 | super(props);
9 | }
10 |
11 | render() {
12 | return (
13 |
14 |
15 |
16 | );
17 | }
18 | }
19 |
20 | export default StaticContainer;
21 |
--------------------------------------------------------------------------------
/server/models/stackModels.js:
--------------------------------------------------------------------------------
1 | // URI to the postgres database is in .env file which is not commited to github. Please request URI from previous team
2 | // Database contains 3 tables for technology Libraries, Framework, and Types
3 |
4 | // import PG_URI from '../../.env';
5 | const { Pool } = require('pg');
6 |
7 | require("dotenv").config();
8 |
9 | // create a new pool here using the connection string above
10 | const pool = new Pool({
11 | connectionString: process.env.PG_URI
12 | });
13 |
14 | // We export an object that contains a property called query,
15 | // which is a function that returns the invocation of pool.query() after logging the query
16 | // This will be required in the controllers to be the access point to the database
17 | module.exports = {
18 | query: (text, params, callback) => {
19 | console.log('executed query', text);
20 | return pool.query(text, params, callback);
21 | }
22 | };
--------------------------------------------------------------------------------
/client/components/containers/mainContainer.tsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import StaticContainer from './staticContainer';
3 | import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
4 | import MakeMap from '../MakeMap';
5 |
6 | // import MainContainer from './containers/MainContainer';
7 | class MainContainer extends Component {
8 | constructor(props) {
9 | super(props);
10 | }
11 | // router set up to render make map on clicking the button
12 | render() {
13 | return (
14 |
15 |
16 |
17 |
18 |
Bubble Stack
19 |
20 | Create New Stack
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | );
35 | }
36 | }
37 | export default MainContainer;
38 |
--------------------------------------------------------------------------------
/server/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const app = express();
3 |
4 | const path = require('path');
5 | const PORT = 3000;
6 | const apiRouter = require('./routes/api');
7 |
8 | app.use(express.json());
9 |
10 | // statically serve everything in the build folder on the route '/build
11 | if (process.env.NODE_ENV === 'production') {
12 | app.use('/', express.static('client'));
13 | app.use('/build', express.static(path.join(__dirname, '../build')));
14 | }
15 |
16 | app.use('/api', apiRouter);
17 |
18 | app.get('/make', (req, res) => {
19 | res.sendFile(path.join(__dirname, '../client/index.html'), (error) => {
20 | if (error) res.status(400).send(error)
21 | })
22 | })
23 |
24 | // global error handler
25 | app.use('*', (req, res) => res.sendStatus(404));
26 |
27 | app.use((err, req, res, next) => {
28 | const defaultErr = {
29 | log: 'Express error handler caught unknown middleware error',
30 | status: 400,
31 | message: { err: 'An error occurred' }
32 | };
33 | const errorObj = { ...defaultErr, ...err };
34 | return res.status(errorObj.status).json(errorObj.message);
35 | });
36 | app.listen(PORT, () => {
37 | console.log(`Server listening on port: ${PORT}`);
38 | });
39 |
40 | module.exports = app;
41 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | entry: './client/index.tsx',
5 | output: {
6 | path: path.resolve(__dirname, 'build'),
7 | filename: 'bundle.js'
8 | },
9 | mode: process.env.NODE_ENV,
10 | devtool: 'source-map',
11 | module: {
12 | rules: [
13 | {
14 | test: /\.(js|jsx)$/,
15 | exclude: /node_modules/,
16 | use: {
17 | loader: 'babel-loader',
18 | options: {
19 | presets: ['@babel/preset-env', '@babel/preset-react']
20 | }
21 | }
22 | },
23 | {
24 | test: /.(css|scss)$/,
25 | exclude: /node_modules/,
26 | use: ['style-loader', 'css-loader', 'sass-loader']
27 | },
28 | {
29 | test: /\.tsx?$/,
30 | exclude: /node_modules/,
31 | loader: 'ts-loader'
32 | },
33 | {
34 | enforce: 'pre',
35 | test: /\.js$/,
36 | loader: 'source-map-loader'
37 | }
38 | ]
39 | },
40 | resolve: {
41 | extensions: ['.tsx', '.ts', '.js']
42 | },
43 | devServer: {
44 | contentBase: path.join(__dirname, '/client'),
45 | publicPath: 'http://localhost:8080/build/',
46 | proxy: {
47 | '/api': 'http://localhost:3000',
48 | '/make': 'http://localhost:3000'
49 | }
50 | }
51 | };
52 |
--------------------------------------------------------------------------------
/client/components/map.js:
--------------------------------------------------------------------------------
1 | import React, { Component, useState, useEffect } from 'react';
2 | import Bubble from './Bubble';
3 |
4 | function Map() {
5 | const [data, setData] = useState({
6 | name: 'React',
7 | loc: 10000,
8 | children: []
9 | });
10 |
11 | useEffect(() => {
12 | fetch('/api/')
13 | .then((res) => res.json())
14 | .then((data) => {
15 | console.log('PAGE RENDER: ', data);
16 | //let chilrenArray = [...this.state]
17 | const newArray = [];
18 | for (let i = 0; i < data.length; i++) {
19 | data[i].loc = 2000;
20 |
21 | if (data[i].type === 'state-management') {
22 | data[i].color = 'hsl(228, 70%, 50%)';
23 | } else if (data[i].type === 'ui-components') {
24 | data[i].color = 'hsl(24, 70%, 50%)';
25 | } else if (data[i].type === 'router') {
26 | data[i].color = 'hsl(156, 70%, 50%)';
27 | }
28 | newArray.push(data[i]);
29 | }
30 | //console.log('NEW ARRAY: ', newArray);
31 | setData({
32 | name: 'React',
33 | loc: 10000,
34 | children: newArray
35 | });
36 | })
37 | .catch((err) => console.log('Map.componentDidMount: ERROR: ', err));
38 | });
39 |
40 | return (
41 |
42 |
43 |
44 | );
45 | }
46 |
47 | export default Map;
48 |
--------------------------------------------------------------------------------
/client/components/Bubble.tsx:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { ResponsiveBubbleHtml } from '@nivo/circle-packing';
3 |
4 | // make sure parent container have a defined height when using
5 | // responsive component, otherwise height will be 0 and
6 | // no chart will be rendered.
7 | // website examples showcase many properties,
8 | // you'll often use just a few of them.
9 | // check nivo bubble chart documentation to see the boilerplate and properties
10 |
11 | const Bubble = (props) => {
12 | // opens reactjs website. planned to open each techs respective website onClick of bubble
13 | const openTech = () => {
14 | const url = 'https://reactjs.org/';
15 | window.open(url, '_blank');
16 | };
17 | return (
18 |
38 | );
39 | };
40 |
41 | export default Bubble;
42 |
--------------------------------------------------------------------------------
/client/style.scss:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,600;0,700;0,800;1,300;1,400;1,600;1,700;1,800&display=swap');
2 | @import 'variables';
3 |
4 | body {
5 | font-family: 'Open Sans', sans-serif;
6 | }
7 |
8 | .content {
9 | text-align: center;
10 | }
11 |
12 | .bubbleContainer {
13 | height: 1000px;
14 | transition: margin-left 0.5s;
15 | padding: 20px;
16 | }
17 |
18 | .left-sidebar {
19 | height: 100%; /* 100% Full-height */
20 | width: 250px; /* 0 width - change this with JavaScript */
21 | position: fixed; /* Stay in place */
22 | z-index: 1; /* Stay on top */
23 | top: 0; /* Stay at the top */
24 | left: 0;
25 | background-color: $primary;
26 | overflow-x: hidden; /* Disable horizontal scroll */
27 | padding-top: 60px; /* Place content 60px from the top */
28 | transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */
29 | }
30 |
31 | .left-sidebar summary {
32 | padding: 8px 8px 8px 32px;
33 | text-decoration: none;
34 | font-size: 25px;
35 | color: #ffffff;
36 | display: block;
37 | transition: 0.3s;
38 | background-color: $primary;
39 | border: 1px solid $primary;
40 | outline: none;
41 | }
42 |
43 | .left-sidebar summary:hover {
44 | color: #b0a2d6;
45 | cursor: pointer;
46 | }
47 |
48 | .collapsible-content button {
49 | background-color: $primary;
50 | border: 1px solid $primary;
51 | outline: none;
52 | display: block;
53 | color: #ffffff;
54 | font-size: 17px;
55 | text-decoration: none;
56 | }
57 |
58 | .collapsible-content button:hover {
59 | color: #b0a2d6;
60 | cursor: pointer;
61 | }
62 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bubble-stack",
3 | "version": "1.0.0",
4 | "description": "bubble-stack",
5 | "main": "index.ts",
6 | "scripts": {
7 | "start": "cross-env NODE_ENV=production webpack & cross-env NODE_ENV=production nodemon server/server.js",
8 | "server": "cross-env NODE_ENV=production webpack",
9 | "dev": "concurrently \"cross-env NODE_ENV=development webpack-dev-server --open --hot\" \"cross-env NODE_ENV=development nodemon ./server/server.js\"",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/Star-Nosed-Mole/Scratch.git"
15 | },
16 | "author": "",
17 | "license": "ISC",
18 | "bugs": {
19 | "url": "https://github.com/Star-Nosed-Mole/Scratch/issues"
20 | },
21 | "homepage": "https://github.com/Star-Nosed-Mole/Scratch#readme",
22 | "dependencies": {
23 | "@nivo/circle-packing": "^0.62.0",
24 | "dotenv": "^8.2.0",
25 | "express": "^4.17.1",
26 | "npm-stats-api": "^1.1.3",
27 | "pg": "^8.3.0",
28 | "react": "^16.13.1",
29 | "react-dom": "^16.13.1",
30 | "react-hot-loader": "^4.12.21",
31 | "react-router": "^5.2.0",
32 | "react-router-dom": "^5.2.0",
33 | "typescript": "^3.9.7"
34 | },
35 | "devDependencies": {
36 | "@babel/core": "^7.10.5",
37 | "@babel/preset-env": "^7.10.4",
38 | "@babel/preset-react": "^7.10.4",
39 | "babel-loader": "^8.1.0",
40 | "concurrently": "^5.2.0",
41 | "cross-env": "^7.0.2",
42 | "css-loader": "^3.6.0",
43 | "nodemon": "^2.0.4",
44 | "sass": "^1.26.10",
45 | "sass-loader": "^9.0.2",
46 | "source-map-loader": "^1.0.1",
47 | "style-loader": "^1.2.1",
48 | "ts-loader": "^8.0.1",
49 | "webpack": "^4.44.0",
50 | "webpack-cli": "^3.3.12",
51 | "webpack-dev-server": "^3.11.0"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/server/routes/api.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const modelsController = require('../controllers/stackControllers');
3 | const router = express.Router();
4 |
5 | // Backend API Requests
6 | // GET to '/'
7 | // Retrieve all libraries and properties(types and frameworks)
8 |
9 | // POST to '/getLibrary' { "library": value }
10 | // Retrieve ONE library and its properties
11 |
12 | // GET to '/getTypes'
13 | // Retrieve all types
14 |
15 | // POST to '/getFramework' { "framework": value }
16 | // Retrieve libraries and corresponding types for ONE framework
17 |
18 | // POST to '/addType' { "type": value }
19 | // Add new type to database
20 |
21 | // POST to '/deleteType' { "type": value }
22 | // Remove type from database
23 |
24 | // POST to '/addFramework' { "framework": value }
25 | // Add new framework to database
26 |
27 | // POST to '/deleteFramework' { "framework": value }
28 | // Remove framework from database
29 |
30 | // POST to '/addLibrary' { "library": value, "framework": value, "type": value }
31 | // Add new library to database
32 |
33 | // POST to '/deleteLibrary' { "library": value }
34 | // Remove library from database
35 |
36 | //route get all libraries of all types and frameworks
37 | router.get('/', modelsController.getAll, (req, res) => {
38 | res.status(200).json(res.locals.all);
39 | });
40 |
41 | // route get ONE specific library's information
42 | router.post(
43 | '/getLibrary',
44 | modelsController.updateLoc,
45 | modelsController.getLibrary,
46 | (req, res) => {
47 | res.status(200).json(res.locals.one);
48 | }
49 | );
50 |
51 | //route retrieve types
52 | router.get('/getTypes', modelsController.getTypes, (req, res) => {
53 | res.status(200).json(res.locals.types);
54 | });
55 |
56 | //route retrieve all information for a specific framework
57 | router.post('/getFramework', modelsController.getFramework, (req, res) => {
58 | res.status(200).json(res.locals.framework);
59 | });
60 |
61 | //REQUESTS TO CREATE/DELETE IN THE DATABASE
62 | //route add type
63 | router.post('/addType', modelsController.addType, (req, res) => {
64 | res.sendStatus(200);
65 | });
66 |
67 | //route delete type
68 | router.post('/deleteType', modelsController.deleteType, (req, res) => {
69 | res.sendStatus(200);
70 | });
71 |
72 | //route add framework
73 | router.post('/addFramework', modelsController.addFramework, (req, res) => {
74 | res.sendStatus(200);
75 | });
76 |
77 | //route delete framework
78 | router.post(
79 | '/deleteFramework',
80 | modelsController.deleteFramework,
81 | (req, res) => {
82 | res.sendStatus(200);
83 | }
84 | );
85 |
86 | //route add library
87 | router.post('/addLibrary', modelsController.addLibrary, (req, res) => {
88 | res.sendStatus(200);
89 | });
90 |
91 | //route delete library
92 | router.post('/deleteLibrary', modelsController.deleteLibrary, (req, res) => {
93 | res.sendStatus(200);
94 | });
95 |
96 | module.exports = router;
97 |
--------------------------------------------------------------------------------
/client/components/MakeMap.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Bubble from './Bubble';
3 | import { findConfigFile } from 'typescript';
4 |
5 | // import MainContainer from './containers/MainContainer';
6 | class MakeMap extends Component {
7 | constructor(props) {
8 | super(props);
9 | // bubble chart initial state.
10 | this.state = {
11 | name: 'React',
12 | color: 'hsl(191, 70%, 50%)',
13 | loc: 10000,
14 | children: [],
15 | show: false
16 | };
17 |
18 | this.getData = this.getData.bind(this);
19 | this.hideBtn = this.hideBtn.bind(this);
20 | }
21 |
22 | // showModal = () => {
23 | // this.setState({ show: true });
24 | // };
25 |
26 | // hideModal = () => {
27 | // this.setState({ show: false });
28 | // };
29 |
30 | componentDidMount() {
31 | this.hideBtn();
32 | }
33 |
34 | hideBtn() {
35 | let d = document.getElementById('stack-btn');
36 | d.style.display = 'none';
37 | }
38 | // post request passing string of text from onClick in navbar to backend for query
39 | getData(tech) {
40 | fetch('/api/getLibrary', {
41 | method: 'POST',
42 | headers: {
43 | 'Content-Type': 'application/json'
44 | },
45 | body: JSON.stringify({ library: tech })
46 | })
47 | .then((res) => res.json())
48 | .then((data) => {
49 | // create bubble object to add to bubble charts children array for rendering
50 | let innerBubble = {};
51 | // assign aliases for name and loc from
52 | let name = data.name;
53 | let loc = data.loc;
54 | // create shallow copy of state's children array to manipulate
55 | let childrenArray = [...this.state.children];
56 | // boolean flag to check if the tech alreay exists in the children array
57 | let nameExists = false;
58 | for (let i = 0; i < childrenArray.length; i++) {
59 | // if a bubble object already exists with name property (because the user has already clicked on that tech)
60 | if (childrenArray[i].name === data.name) {
61 | nameExists = true;
62 | // remove that element from the array
63 | childrenArray.splice(i, 1);
64 | }
65 | }
66 | // if know tech is found after iterating through children array we will build out the innerBubble object
67 | if (nameExists === false) {
68 | // add properties and/or values to bubble objects
69 | // conditional statements are to assign colors to bubbles
70 | innerBubble.name = name;
71 | innerBubble.description = 'DESCRIPTION';
72 | innerBubble.loc = loc;
73 | if (data.type === 'state-management') {
74 | innerBubble.color = 'hsl(228, 70%, 50%)';
75 | } else if (data.type === 'ui-components') {
76 | innerBubble.color = 'hsl(24, 70%, 50%)';
77 | } else if (data.type === 'router') {
78 | innerBubble.color = 'hsl(156, 70%, 50%)';
79 | }
80 | // push innerBubble object to childrenArray
81 | childrenArray.push(innerBubble);
82 | }
83 | // update state with childrenArray.
84 | this.setState({
85 | ...this.state,
86 | children: childrenArray
87 | });
88 | });
89 | }
90 |
91 | render() {
92 | return (
93 |
94 |
95 |
96 | State Management
97 |
98 | {/* fire getData method onClick and pass in the tech they clicked on in the navbar */}
99 | this.getData('redux')}>Redux
100 | this.getData('recoil')}>Recoil
101 | this.getData('mobx')}>MobX
102 |
103 |
104 |
105 |
106 | UI Components
107 |
108 | this.getData('material-ui')}>
109 | Material UI
110 |
111 | this.getData('react-bootstrap')}>
112 | React Bootstrap
113 |
114 | this.getData('rebass')}>Rebass
115 |
116 |
117 |
118 |
119 |
120 | {/* pass state down to bubble chart */}
121 |
122 |
123 |
124 | );
125 | }
126 | }
127 |
128 | export default MakeMap;
129 |
--------------------------------------------------------------------------------
/server/controllers/stackControllers.js:
--------------------------------------------------------------------------------
1 | const db = require('../models/stackModels');
2 | const { stack } = require('../routes/api');
3 | const npm = require('npm-stats-api');
4 |
5 | const stackController = {};
6 |
7 | /*
8 | The npm.stats.api allows us to get the number of npm downloads each tech stack has.
9 | We didn't want to refresh the data and fetch from the api with every get or post request because the numbers are big enough that refreshing every
10 | 5 days would've sufficed. The below is us checking for the last updated day - if it's been 5 or more days since the last update,
11 | we will make a request to the api and store the information as one SQL query into a variable called passing which we will query
12 | in the middleware stockController.updateLoc
13 | */
14 | // day is last updated day
15 | let day = 11; /* day is currently hard coded in, but need to find a way to update day every time we update, didn't have time to figure this part out */
16 | // getting today's date
17 | let date = new Date();
18 | // getting the day of today's date (e.g., if it's July 27, today = 27)
19 | let today = date.getDate();
20 | // formatting the date to match the syntax required for API parameter
21 | let formattedDate = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}`;
22 | // creating an array to store all the queries we will be creating below
23 | let queryUpdateLibrary = [];
24 | // we will be using the join method to combine the queryUpdateLibrary array elements into one string, so we are declaring the variable of this string here
25 | let passing = '';
26 | // if it has been 5 or more days since the last update
27 | if (today > day + 5) {
28 | // reassign last updated day to be today's date
29 | day = today;
30 | // SQL query to get all names from the libraries table
31 | const queryGetNames = `SELECT name FROM libraries`;
32 | db.query(queryGetNames)
33 | .then((data) => {
34 | // data.rows comes back as an array of objects (console.log to see what this looks like for reference) so we will iterate through this array
35 | data.rows.forEach((tech) => {
36 | // for each el in array (console.log for reference), we will use the below API method to get the number of downloads and store that as a column called 'loc' in the libraries table
37 | // the parameters required for npm.stat is npm.stat(name of tech - string - e.g., 'redux' , range from date, range to date, callback function)
38 | npm.stat(tech.name, '2020-01-01', `${formattedDate}`, (err, response) => {
39 | // push this query into queryUpdateLibrary - had to divide by 1000 because numbers were too large
40 | queryUpdateLibrary.push(`UPDATE libraries SET loc = ${Math.floor(response.downloads/1000)} WHERE name = '${tech.name}';`)
41 | // concat arr els to be one string
42 | passing = queryUpdateLibrary.join(' ');
43 | })
44 | });
45 | })
46 | .catch((err) => {
47 | return err;
48 | });
49 | }
50 | // retrieve info from all libraries
51 | stackController.getAll = (req, res, next) => {
52 | const queryAll = `SELECT libraries.name, types.name AS type, framework.name AS framework FROM libraries
53 | INNER JOIN types ON libraries.type_id = types.type_id
54 | INNER JOIN framework ON libraries.framework_id = framework.framework_id;`;
55 |
56 | db.query(queryAll)
57 | .then((data) => {
58 | res.locals.all = data.rows;
59 | return next();
60 | })
61 | .catch((err) => {
62 | return next(err);
63 | });
64 | };
65 |
66 | // retrieve information for a specific library
67 | stackController.getLibrary = (req, res, next) => {
68 | const name = req.body.library;
69 | const queryOne = `SELECT libraries.name, libraries.loc, types.name AS type, framework.name AS framework FROM libraries
70 | INNER JOIN types ON libraries.type_id = types.type_id
71 | INNER JOIN framework ON libraries.framework_id = framework.framework_id
72 | WHERE libraries.name = '${name}'; `;
73 | db.query(queryOne)
74 | .then((data) => {
75 | console.log(data.rows[0]);
76 | res.locals.one = data.rows[0];
77 | console.log('RESLOCALSONE ', res.locals.one);
78 | return next();
79 | })
80 | .catch((err) => {
81 | return next(err);
82 | });
83 | };
84 |
85 | // update loc column in libraries table
86 | stackController.updateLoc = (req, res, next) => {
87 | // console.log('passing', passing);
88 | db.query(passing)
89 | .then(() => {
90 | // console.log('SUCCESS');
91 | return next();
92 | })
93 | .catch((err) => {
94 | return next(err);
95 | });
96 | };
97 |
98 | //retrieve types
99 | stackController.getTypes = (req, res, next) => {
100 | const queryTypes = `SELECT * FROM types;`;
101 |
102 | db.query(queryTypes)
103 | .then((data) => {
104 | console.log(data.rows);
105 | res.locals.types = data.rows;
106 | return next();
107 | })
108 | .catch((err) => {
109 | return next(err);
110 | });
111 | };
112 |
113 | //retrieve all libraries for a specific framework
114 | stackController.getFramework = (req, res, next) => {
115 | const name = req.body.framework;
116 | const queryFramework = `SELECT libraries.name, types.name AS type FROM libraries
117 | INNER JOIN types ON libraries.type_id = types.type_id
118 | INNER JOIN framework ON libraries.framework_id = framework.framework_id
119 | WHERE framework.name = '${name}';`;
120 |
121 | db.query(queryFramework)
122 | .then((data) => {
123 | console.log(data.rows);
124 | res.locals.framework = data.rows;
125 | return next();
126 | })
127 | .catch((err) => {
128 | return next(err);
129 | });
130 | };
131 |
132 | //add type
133 | stackController.addType = (req, res, next) => {
134 | const type = req.body.type;
135 | const queryType = `INSERT INTO types VALUES ('${type}');`;
136 |
137 | db.query(queryType)
138 | .then((data) => {
139 | return next();
140 | })
141 | .catch((err) => {
142 | return next(err);
143 | });
144 | };
145 |
146 | //delete type
147 | stackController.deleteType = (req, res, next) => {
148 | const type = req.body.type;
149 | const queryType = `DELETE FROM types WHERE name = '${type}';`;
150 |
151 | db.query(queryType)
152 | .then((data) => {
153 | return next();
154 | })
155 | .catch((err) => {
156 | return next(err);
157 | });
158 | };
159 |
160 | //add framework
161 | stackController.addFramework = (req, res, next) => {
162 | const framework = req.body.framework;
163 | const queryFramework = `INSERT INTO framework (name) VALUES ('${framework}');`;
164 |
165 | db.query(queryFramework)
166 | .then((data) => {
167 | return next();
168 | })
169 | .catch((err) => {
170 | return next(err);
171 | });
172 | };
173 |
174 | //delete framework
175 | stackController.deleteFramework = (req, res, next) => {
176 | const framework = req.body.framework;
177 | const queryFramework = `DELETE FROM framework WHERE name = '${framework}';`;
178 |
179 | db.query(queryFramework)
180 | .then((data) => {
181 | return next();
182 | })
183 | .catch((err) => {
184 | return next(err);
185 | });
186 | };
187 |
188 | //add library
189 | stackController.addLibrary = (req, res, next) => {
190 | const library = req.body.library;
191 | const framework = req.body.framework;
192 | const type = req.body.type;
193 | const queryLibrary = `INSERT INTO libraries (name, framework_id, type_id) VALUES ('${library}',
194 | (SELECT framework_id FROM framework WHERE framework.name = '${framework}'),
195 | (SELECT type_id FROM types WHERE types.name = '${type}'));`;
196 |
197 | db.query(queryLibrary)
198 | .then((data) => {
199 | return next();
200 | })
201 | .catch((err) => {
202 | return next(err);
203 | });
204 | };
205 |
206 | //delete library
207 | stackController.deleteLibrary = (req, res, next) => {
208 | const library = req.body.library;
209 | const queryLibrary = `DELETE FROM libraries WHERE name = '${library}';`;
210 |
211 | db.query(queryLibrary)
212 | .then((data) => {
213 | return next();
214 | })
215 | .catch((err) => {
216 | return next(err);
217 | });
218 | };
219 |
220 | module.exports = stackController;
221 |
--------------------------------------------------------------------------------