Initial node additions

pull/1/head
Rob Hedgpeth 2019-11-09 06:19:46 -06:00
rodzic d5236c8ec3
commit 1a6fb2fe7b
11 zmienionych plików z 1476 dodań i 0 usunięć

162
Places/README.md 100644
Wyświetl plik

@ -0,0 +1,162 @@
# Places
**Places** is a web application written in [ReactJS](https://reactjs.org) and [NodeJS](https://nodejs.org) that, backed by the power of the [MariaDB Node Connector](https://github.com/MariaDB/mariadb-connector-nodejs) and [MariaDB platform](https://mariadb.com/products/mariadb-platform/), allows you to record all of your favorite locations!
<p align="center">
<img src="media/map.png" />
</p>
This `README` will walk you through the steps for getting this app up and running (locally) within minutes!
# Table of Contents
1. [Overview](#overview)
1. [Introduction to MariaDB](#intro-mariadb)
2. [Using JSON in a relational database](#json-relational)
2. [Requirements](#requirements)
3. [Getting started](#getting-started)
1. [Grab the code](#grab-code)
2. [Build the code](#build-code)
3. [Run the app](#run-app)
4. [Support and Contribution](#support-contribution)
## Overview <a name="overview"></a>
### Introduction to MariaDB <a name="intro-mariadb"></a>
[MariaDB platform](https://mariadb.com/products/mariadb-platform/) unifies [MariaDB TX (transactions)](https://mariadb.com/products/mariadb-platform-transactional/) and [MariaDB AX (analytics)](https://mariadb.com/products/mariadb-platform-analytical/) so transactional applications can retain unlimited historical data and leverage powerful, real-time analytics in order to provide data-driven customers with more information, actionable insight and greater value – and businesses with endless ways to monetize data. It is the enterprise open source database for hybrid transactional/analytical processing at scale.
<p align="center">
<img src="media/platform.png" />
</p>
### Using JSON in a relational database <a name="json-relational"></a>
[JSON](https://www.json.org) is fast becoming the standard format for data interchange and for unstructured data, and MariaDB Platform (in fact, all MariaDB versions 10.2 and later) include a range of [JSON supporting functions](https://mariadb.com/topic/json/).
The Places application uses only a **single table** for all location, and uses JSON to store more specific information based on the location type.
```sql
CREATE TABLE `Locations` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL DEFAULT '',
`description` varchar(500) DEFAULT '',
`type` char(1) NOT NULL DEFAULT '',
`latitude` decimal(9,6) NOT NULL,
`longitude` decimal(9,6) NOT NULL,
`attr` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`attr`)),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4;
```
For more information on how JSON can be used within MariaDB please check out this [blog post](https://mariadb.com/resources/blog/json-with-mariadb-10-2/)!
## Requirements <a name="requirements"></a>
This project assumes you have familiarity with building web applications using ReactJS and NodeJS technologies.
* Download and install [MariaDB](https://go.mariadb.com/download-mariadb-server-community.html?utm_source=google&utm_medium=ppc&utm_campaign=MKG-Search-Google-Branded-DL-NA-Server-DL&gclid=CjwKCAiAwZTuBRAYEiwAcr67OUBIqnFBo9rUBhYql3VZV_nhlSKzkwoUv7vhA6gwNdGoBSc2uWe7SBoCX_oQAvD_BwE).
* Download and install [NodeJS](https://nodejs.org/).
* git (Optional) - this is required if you would prefer to pull the source code from GitHub repo.
- Create a [free github account](https://github.com/) if you dont already have one
- git can be downloaded from git-scm.org
## Getting started <a name="getting-started"></a>
In order to run the Places application you will need to have a MariaDB instance to connect to. For more information please check out "[Get Started with MariaDB](https://mariadb.com/get-started-with-mariadb/)".
In order to build and run the Places applications you will need to have NodeJS installed. You can find more information [here](https://nodejs.org/).
### Create the schema <a name="create-schema"></a>
Using CLI or SQL client run the following SQL command:
```sql
CREATE TABLE `Locations` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL DEFAULT '',
`description` varchar(500) DEFAULT '',
`type` char(1) NOT NULL DEFAULT '',
`latitude` decimal(9,6) NOT NULL,
`longitude` decimal(9,6) NOT NULL,
`attr` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL CHECK (json_valid(`attr`)),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4;
```
### Grab the code <a name="grab-code"></a>
Download this code directly or use [git](git-scm.org) (through CLI or a client) to retrieve the code.
### Configure the code <a name="configure-code"></a>
**The gist;** Add a Google Maps API Key and database connection information to the code.
1. Once you've obtained a Google Maps API Key place add it to the code [here](src/client/src/components/MapContainer.js#245).
```js
export default GoogleApiWrapper({
apiKey: ("reallllllylongkeyhere")
})(MapContainer)
```
2. Update the MariaDB connection configuration here.
```js
const pool = mariadb.createPool({
host: 'localhost',
user:'root',
password: 'sosafemuchsecure',
database: 'Places',
multipleStatements: true,
connectionLimit: 5
});
```
### Build the code <a name="build-code"></a>
Now that you have a copy of the code you're ready to build and run the project. However, before running the code it's important to point out that the application uses several Node Packages.
For the client-side:
- [google-maps-react](https://www.npmjs.com/package/google-map-react)
- [props-type](https://www.npmjs.com/package/props-type)
- [react](https://www.npmjs.com/package/react)
- [react-datepicker](https://www.npmjs.com/package/react-datepicker)
- [react-dom](https://www.npmjs.com/package/react-dom)
- [react-modal](https://www.npmjs.com/package/react-modal)
- [react-scripts](https://www.npmjs.com/package/react-scripts)
For the server-side:
- [body-parser](https://www.npmjs.com/package/body-parser)
- [concurrently](https://www.npmjs.com/package/concurrently)
- [express](https://www.npmjs.com/package/express)
- [mariadb](https://www.npmjs.com/package/mariadb) (the best database in world)
### Run the app <a name="run-app"></a>
Once you've pulled down the code and have verified that all of the required Node packages are installed you're ready to run the application! It's as easy as 1,2,3.
1. Using a command line interface (CLI) navigate to where to the `src` directory of Places.
<p align="center">
<img src="media/cli_root.png" />
</p>
2. Run the command:
```bash
npm start
```
<p align="center">
<img src="media/npm_start.png" />
</p>
3. Open a browser window and navigate to http://localhost:3000.
## Support and Contribution <a name="support-contribution"></a>
Thanks so much for taking a look at the Places app! As this is a very simple example,there's a lot of potential for customization!
If you have any questions, comments, or would like to contribute to this or future projects like this please reach out to us directly at developers@mariadb.com or on [Twitter](https://twitter.com/mariadb).

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 125 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 443 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 432 KiB

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 233 KiB

61
Places/src/.gitignore vendored 100644
Wyświetl plik

@ -0,0 +1,61 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next

23
Places/src/db.js 100644
Wyświetl plik

@ -0,0 +1,23 @@
var mariadb = require('mariadb');
// Local Connection
const pool = mariadb.createPool({
host: 'localhost',
user:'root',
password: 'password',
database: 'Places',
multipleStatements: true,
connectionLimit: 5
});
module.exports={
getConnection: function(){
return new Promise(function(resolve,reject){
pool.getConnection().then(function(connection){
resolve(connection);
}).catch(function(error){
reject(error);
});
});
}
}

1042
Places/src/package-lock.json wygenerowano 100644

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,19 @@
{
"name": "places",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "concurrently \"npm run server\" \"npm run client\"",
"server": "node server.js",
"client": "npm start --prefix client"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.19.0",
"concurrently": "^5.0.0",
"express": "^4.17.1",
"mariadb": "^2.1.2"
}
}

Wyświetl plik

@ -0,0 +1,141 @@
"use strict";
let express = require("express"),
router = express.Router(),
pool = require('../db');
// GET all locations
router.get("/", async (req, res, next) => {
let conn;
try {
conn = await pool.getConnection();
var query = "select id, name, type, longitude, latitude, " +
"case when type = 'R' then concat((case when json_length(attr, '$.favorites') " +
"is not null then json_length(attr, '$.favorites') else 0 end), ' favorite meals') " +
"when type = 'A' then (case when json_value(attr, '$.lastVisitDate') is not null " +
"then json_value(attr, '$.lastVisitDate') else 'N/A' end) " +
"when type = 'S' then concat((case when json_length(attr, '$.events') is not null " +
"then json_length(attr, '$.events') else 0 end), ' events') end as description " +
"from Locations";
var rows = await conn.query(query);
res.send(rows);
} catch (err) {
throw err;
} finally {
if (conn) return conn.release();
}
});
// POST new location
router.post("/", async (req, res, next) => {
let location = req.body;
let conn;
try {
conn = await pool.getConnection();
var query = "insert into Locations (name, description, type, latitude, longitude, attr) values (?, ?, ?, ?, ?, json_compact(?))";
var result = await conn.query(query, [location.name, location.description, location.type, location.latitude, location.longitude, JSON.stringify(location.attr)]);
res.send(result);
} catch (err) {
throw err;
} finally {
if (conn) return conn.release();
}
});
// GET restaurant by id
router.get("/restaurant", async (req, res, next) => {
let conn;
try {
conn = await pool.getConnection();
var id = req.query.id;
var query = "select " +
"name, " +
"json_value(attr,'$.details.foodType') as foodType, " +
"json_value(attr,'$.details.menu') as menu, " +
"json_query(attr,'$.favorites') as favorites " +
"from Locations " +
"where id = ?";
var rows = await conn.query(query, [id]);
res.send(rows[0]);
} catch (err) {
throw err;
} finally {
if (conn) return conn.release();
}
});
// POST new restaurant favorite
router.post("/restaurant/favorites", async (req, res, next) => {
let favorite = req.body;
let details = favorite.details;
let conn;
try {
conn = await pool.getConnection();
var query = "update Locations set attr = json_array_append(attr, '$.favorites', json_compact(?)) where id = ?"
var result = await conn.query(query, [JSON.stringify(details), favorite.locationid]);
res.send(result);
} catch (err) {
throw err;
} finally {
if (conn) return conn.release();
}
});
// GET sports venue by id
router.get("/sportsvenue", async (req, res, next) => {
let conn;
try {
conn = await pool.getConnection();
var id = req.query.id;
var query = "select " +
"name, " +
"json_value(attr,'$.details.yearOpened') as yearOpened, " +
"json_value(attr,'$.details.capacity') as capacity, " +
"json_query(attr,'$.events') as events " +
"from Locations " +
"where id = ?";
var rows = await conn.query(query, [id]);
res.send(rows[0]);
} catch (err) {
throw err;
} finally {
if (conn) return conn.release();
}
});
// POST new sports venue event
router.post("/sportsvenue/event", async (req, res, next) => {
let event = req.body;
let conn;
try {
conn = await pool.getConnection();
var query = "update Locations set attr = json_array_append(attr, '$.events', json_compact(?)) where id = ?";
var result = await conn.query(query, [JSON.stringify(event.details), event.locationid]);
res.send(result);
} catch (err) {
throw err;
} finally {
if (conn) return conn.release();
}
});
// PUT last visited an attraction
router.put("/attractions", async (req, res, next) => {
let locationId = req.query.id;
let lastVisitDate = req.query.dt;
let conn;
try {
conn = await pool.getConnection();
var query = "update Locations set attr = json_set(attr,'$.lastVisitDate', ?) where id = ?";
var result = await conn.query(query, [lastVisitDate, locationId]);
res.send(result);
} catch (err) {
throw err;
} finally {
if (conn) return conn.release();
}
});
module.exports = router;

Wyświetl plik

@ -0,0 +1,28 @@
const express = require('express');
const app = express();
const port = 8080;
const path = require('path');
const bodyParser = require("body-parser");
const locationRoutes = require("./routes/locationRoutes");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
if (process.env.NODE_ENV === 'production') {
app.use(express.static('client/build'));
}
app.use("/api/locations", locationRoutes);
app.get("/*", (req, res) => {
res.sendFile(path.join(__dirname, "/client/build/index.html"));
});
app.use((err, req, res, next) => {
res.status(422).send({ error: err._message });
});
// console.log that your server is up and running
app.listen(port, () => console.log(`Listening on port ${port}`));