including CAIT data, models and seeds

This commit is contained in:
Eric Hulburd
2016-01-26 19:42:30 -06:00
commit 220ddfed19
47 changed files with 16607 additions and 0 deletions

3
.babelrc Normal file
View File

@@ -0,0 +1,3 @@
{
"presets": ["es2015", "stage-0", "react"]
}

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
node_modules/
bin/

137
app.express.js Normal file
View File

@@ -0,0 +1,137 @@
/*
* Serve GraphQL Backend
*/
import express from 'express';
import graphQLHTTP from 'express-graphql';
import path from 'path';
import webpack from 'webpack';
import WebpackDevServer from 'webpack-dev-server';
import {Schema} from './data/schema';
const APP_PORT = 3000;
const GRAPHQL_PORT = 8080;
var graphql_server = express();
// Expose a GraphQL endpoint
graphql_server.use('/', graphQLHTTP({
graphiql: true,
pretty: true,
schema: Schema,
}));
graphql_server.listen(GRAPHQL_PORT, () => console.log(
`GraphQL Server is now running on http://localhost:${GRAPHQL_PORT}`
));
/*
* Compile and Serve Relay App w/ Webpack
*/
var compiler = webpack({
entry: {
app: path.resolve(__dirname, 'relay', 'application.js')
},
module: {
loaders: [
{
exclude: /node_modules/,
loader: 'babel',
query: {
plugins: ['./build/babelRelayPlugin'],
},
test: /\.js$/
}
]
},
output: {filename: 'application.js', path: '/'}
});
var dev_server = new WebpackDevServer(compiler, {
contentBase: '/public/',
proxy: {'/graphql': `http://localhost:${GRAPHQL_PORT}`},
publicPath: '/assets/js/',
stats: {colors: true}
});
/*
* Logging, Cookie, JSON Parsing Middleware
*
import favicon from 'serve-favicon';
import logger from 'morgan';
import cookieParser from 'cookie-parser';
import bodyParser from 'bodyParser';
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());*/
/*
* Serve Vendor Scripts, CSS, and Templates
*/
// serve fonts in /assets/fonts
import assets from "connect-assets";
dev_server.app.use("/assets/fonts", express.static("node_modules/bootstrap/dist/fonts"));
dev_server.app.use("/assets/fonts", express.static("node_modules/font-awesome/fonts"));
// serve compiled vendor assets and application.css.
dev_server.app.use(assets({
paths: ["assets/js", "assets/css", "node_modules"],
build: true,
buildDir: false,
//compile: false,
compress: true
}));
// serve public static files.
dev_server.app.use('/', express.static(path.resolve(__dirname, 'public')));
// view engine set up
dev_server.app.set('views', path.join(__dirname, 'views'));
dev_server.app.set('view engine', 'jade');
dev_server.app.get("/", (req, res, next)=>{
res.render("index");
});
dev_server.listen(APP_PORT, () => {
console.log(`App is now running on http://localhost:${APP_PORT}`);
});
/*
* Handle Errors
*/
// catch 404 and forward to error handler
dev_server.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
/*
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});*/
module.exports = dev_server;

View File

View File

@@ -0,0 +1,3 @@
/*=require bootstrap/dist/css/bootstrap.min
*= require font-awesome/css/font-awesome.min
*/

3
assets/js/vendor.js Normal file
View File

@@ -0,0 +1,3 @@
//= require d3/d3.min
//= require jquery/dist/jquery.min
//= require bootstrap/dist/js/bootstrap.min

View File

@@ -0,0 +1,4 @@
var getbabelRelayPlugin = require('babel-relay-plugin'),
schema = require('../data/schema.json');
module.exports = getbabelRelayPlugin(schema.data, {abortOnError: true});

40
config/database.js Normal file
View File

@@ -0,0 +1,40 @@
"use strict";
var fs = require("fs"),
models = [],
model_path = __dirname + "/../models",
files = fs.readdirSync(model_path),
Sequelize = require("sequelize"),
sequelize = new Sequelize("postgres://spikeuser:123456@localhost:5432/spike_proto", {
pool: {
max: 5,
min: 0,
idle: 10000
}
});
class Database {
static sync(){
// define each model
for (var filename of files){
var path = model_path + "/" + filename,
stats = fs.statSync(path)
if (stats.isFile()){
models.push(require(path));
}
}
// add associations
for (var model of models){
model.associate();
}
return sequelize.sync({force: true});
}
}
Database.Sequelize = Sequelize;
Database.sequelize = sequelize;
export Database;

0
data/CAIT/citation.txt Normal file
View File

4325
data/CAIT/emissions.csv Executable file

File diff suppressed because it is too large Load Diff

9965
data/CAIT/socioeconomic.csv Executable file

File diff suppressed because it is too large Load Diff

33
data/database.js Normal file
View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) 2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
// Model types
class User extends Object {}
class Widget extends Object {}
// Mock data
var viewer = new User();
viewer.id = '1';
viewer.name = 'Anonymous';
var widgets = ['What\'s-it', 'Who\'s-it', 'How\'s-it'].map((name, i) => {
var widget = new Widget();
widget.name = name;
widget.id = `${i}`;
return widget;
});
module.exports = {
// Export methods that your schema can use to interact with your database
getUser: (id) => id === viewer.id ? viewer : null,
getViewer: () => viewer,
getWidget: (id) => widgets.find(w => w.id === id),
getWidgets: () => widgets,
User,
Widget,
};

143
data/schema.js Normal file
View File

@@ -0,0 +1,143 @@
/**
* Copyright (c) 2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
import {
GraphQLBoolean,
GraphQLFloat,
GraphQLID,
GraphQLInt,
GraphQLList,
GraphQLNonNull,
GraphQLObjectType,
GraphQLSchema,
GraphQLString,
} from 'graphql';
import {
connectionArgs,
connectionDefinitions,
connectionFromArray,
fromGlobalId,
globalIdField,
mutationWithClientMutationId,
nodeDefinitions,
} from 'graphql-relay';
import {
// Import methods that your schema can use to interact with your database
User,
Widget,
getUser,
getViewer,
getWidget,
getWidgets,
} from './database';
/**
* We get the node interface and field from the Relay library.
*
* The first method defines the way we resolve an ID to its object.
* The second defines the way we resolve an object to its GraphQL type.
*/
var {nodeInterface, nodeField} = nodeDefinitions(
(globalId) => {
var {type, id} = fromGlobalId(globalId);
if (type === 'User') {
return getUser(id);
} else if (type === 'Widget') {
return getWidget(id);
} else {
return null;
}
},
(obj) => {
if (obj instanceof User) {
return userType;
} else if (obj instanceof Widget) {
return widgetType;
} else {
return null;
}
}
);
/**
* Define your own types here
*/
var userType = new GraphQLObjectType({
name: 'User',
description: 'A person who uses our app',
fields: () => ({
id: globalIdField('User'),
widgets: {
type: widgetConnection,
description: 'A person\'s collection of widgets',
args: connectionArgs,
resolve: (_, args) => connectionFromArray(getWidgets(), args),
},
}),
interfaces: [nodeInterface],
});
var widgetType = new GraphQLObjectType({
name: 'Widget',
description: 'A shiny widget',
fields: () => ({
id: globalIdField('Widget'),
name: {
type: GraphQLString,
description: 'The name of the widget',
},
}),
interfaces: [nodeInterface],
});
/**
* Define your own connection types here
*/
var {connectionType: widgetConnection} =
connectionDefinitions({name: 'Widget', nodeType: widgetType});
/**
* This is the type that will be the root of our query,
* and the entry point into our schema.
*/
var queryType = new GraphQLObjectType({
name: 'Query',
fields: () => ({
node: nodeField,
// Add your own root fields here
viewer: {
type: userType,
resolve: () => getViewer(),
},
}),
});
/**
* This is the type that will be the root of our mutations,
* and the entry point into performing writes in our schema.
*/
var mutationType = new GraphQLObjectType({
name: 'Mutation',
fields: () => ({
// Add your own mutations here
})
});
/**
* Finally, we construct our schema (whose starting query type is the query
* type we defined above) and export it.
*/
export var Schema = new GraphQLSchema({
query: queryType,
// Uncomment the following after adding some mutation fields:
// mutation: mutationType
});

1160
data/schema.json Normal file

File diff suppressed because it is too large Load Diff

4
gulpfile.js Normal file
View File

@@ -0,0 +1,4 @@
var gulp = require("gulp"),
seedDate = require("./lib/tasks/seed_data");
gulp.task('seedData', seedData);

5
lib/base.model.js Normal file
View File

@@ -0,0 +1,5 @@
export class Model {
static associate(){}
}

1
lib/d3/bar.d3.js Normal file
View File

@@ -0,0 +1 @@
bar.d3.js

1
lib/d3/base.d3.js Normal file
View File

@@ -0,0 +1 @@
base.d3.js

1
lib/d3/composite.d3.js Normal file
View File

@@ -0,0 +1 @@
composite.d3.js

0
lib/d3/grid.d3.js Normal file
View File

1
lib/d3/line.d3.js Normal file
View File

@@ -0,0 +1 @@
line.d3.js

1
lib/d3/pie.d3.js Normal file
View File

@@ -0,0 +1 @@
pie.d3.js

View File

@@ -0,0 +1 @@
base.widget.js

View File

@@ -0,0 +1 @@
campaign_orders.widget.js

View File

@@ -0,0 +1 @@
energy_time_series.widget.js

View File

@@ -0,0 +1,51 @@
import React from 'react';
import Relay from 'react-relay';
class PowerTimeSeries extends React.Component {
get timeframes(){
return [
{display: "Today", value: 'today'},
{display: "1 week", value: 'week'},
{display: "1 month", value: 'month'},
{display: "6 months", value: 'half_year'},
{display: "1 year", value: 'year'}
];
}
render() {
var power_time_series = this;
return (
<div>
<h1>Power Time Series</h1>
<ul>
{power_time_series.props.viewer.widgets.edges.map(edge =>
<li key={edge.node.id}>{edge.node.name} (ID: {edge.node.id})</li>
)}
</ul>
<div class="spk-power-time-series-timeframes">
{power_time_series.timeframes.map(timeframe =>
<div data-value="{timeframe.value}" class="spk-power-time-series-timeframe">{timeframe.display}</div>
)}
</div>
</div>
);
}
}
export default Relay.createContainer(PowerTimeSeries, {
fragments: {
viewer: () => Relay.QL`
fragment on User {
widgets(first: 10) {
edges {
node {
id,
name,
},
},
},
}
`,
},
});

View File

@@ -0,0 +1 @@
production_radiation_time_series.widget.js

6
lib/dashboard/readme.md Normal file
View File

@@ -0,0 +1,6 @@
## Dashboard Widgets
After initialized:
1. They get/ check the data they need.
2. Render default graph settings.
3. Update graphs based on user input.

27
lib/node.relay.js Normal file
View File

@@ -0,0 +1,27 @@
/**
* We get the node interface and field from the Relay library.
*
* The first method defines the way we resolve an ID to its object.
* The second defines the way we resolve an object to its GraphQL type.
*/
var {nodeInterface, nodeField} = nodeDefinitions(
(globalId) => {
var {type, id} = fromGlobalId(globalId);
if (type === 'PowerDatum') {
return getUser(id);
} else if (type === 'Widget') {
return getWidget(id);
} else {
return null;
}
},
(obj) => {
if (obj instanceof User) {
return userType;
} else if (obj instanceof Widget) {
return widgetType;
} else {
return null;
}
}
);

104
lib/tasks/seed_data.js Normal file
View File

@@ -0,0 +1,104 @@
module.exports = function(done) {
var csv = require("fast-csv"),
Database = require("./config/database"),
Country = require("./models/country"),
Datum = require("./models/datum"),
countries = [],
data = new Map();
function seedEmissions(fn){
var i = -1;
csv
.fromPath(__dirname + "/data/CAIT/emissions.csv")
.on("data", (row)=>{
i += 1;
if (i == 0) return true;
var name = row[0],
year = parseInt(row[1]),
key = name + year,
energy = parseFloat(row[11]) || null,
industrial = parseFloat(row[12]) || null,
agriculture = parseFloat(row[13]) || null,
waste = parseFloat(row[14]) || null,
lucf = parseFloat(row[15]) || null,
total_emissions = Math.max((energy + industrial + agriculture + waste + lucf), parseFloat(row[3])) || null; // MtCO2eq
if (countries.indexOf(name) < 0) countries.push(name);
data.set(key, data.get(key) || {name: name, year: year});
datum = data.get(key);
datum.energy_emissions = energy; // MtCO2eq
datum.industrial_emissions = industrial; // MtCO2eq
datum.agriculture_emissions = agriculture; // MtCO2eq
datum.waste_emissions = waste; // MtCO2eq
datum.lucf_emissions = lucf; // MtCO2eq
datum.total_emissions = total_emissions; // MtCO2eq
})
.on("end", fn);
}
function seedSocioEco(fn){
var i = -1;
csv
.fromPath(__dirname + "/data/CAIT/socioeconomic.csv")
.on("data", (row)=>{
i += 1;
if (i == 0) return true;
var name = row[0],
year = parseInt(row[1]),
key = (name + year),
population = parseInt(row[2]) || null,
gdp = parseFloat(row[4]) || null, // Million 2005 USD
energy = parseFloat(row[5]) || null; // ktoe
if (countries.indexOf(name) < 0) countries.push(name);
data.set(key, data.get(key) || {name: name, year: year});
datum = data.get(key);
datum.population = population;
datum.energy = energy;
datum.gdp = gdp;
})
.on("end", fn);
}
Database.sync().then(()=>{
seedEmissions(()=>{
seedSocioEco(()=>{
Country.sql.bulkCreate(countries.map((name)=>{ return {name: name}; }), {validate: true}).catch((errors)=>{
console.error(`=== Error ===\n${JSON.stringify(errors)}\n`);
}).then(()=>{
return Country.sql.findAll();
}).then((_countries)=>{
var country_name_to_id = new Map();
for (var country of _countries){
country_name_to_id.set(country.name, country.id);
}
for (var datum of data.values()){
datum.country_id = country_name_to_id.get(datum.name);
delete datum["name"];
}
var bulk_data = Array.from(data.values());
Datum.sql.bulkCreate(bulk_data, {validate: true}).catch((errors)=>{
console.error(`=== Error ===\n${JSON.stringify(errors)}\n`);
}).error((err)=>{
console.error(`=== Error ===\n${err}`);
}).then(()=>{
return Datum.sql.count();
}).then((count)=>{
console.log(`Count: ${count} ${bulk_data.length}`)
if (count === bulk_data.length){
done();
} else {
console.log("Error!");
done();
}
});
});
});
});
});
};

54
models/country.js Normal file
View File

@@ -0,0 +1,54 @@
"use strict";
var Database = require("./../config/database");
class Country {
static associate(){
var Datum = require("./datum");
this.sql.hasOne(Datum.sql, {as: "Data", foreignKey: "id", constraints: false});
}
};
Country.sql = Database.sequelize.define('Country', {
id: {
type: Database.Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true // Automatically gets converted to SERIAL for postgres
},
name: {
type: Database.Sequelize.STRING,
unique: true,
allowNull: false
}
}, {tableName: "countries"});
Country.graphql = new GraphQLObjectType({
name: "Country",
description: "A world country",
fields: ()=>{
id: {
type: new GraphQLNonNull(GraphQLInteger)
},
name: {
type: new GraphQLNonNull(GraphQLString)
},
data: {
type: new GraphQLList(Datum.graphql),
args: {
year: {
type: GraphQLList(GraphQLInteger)
}
},
resolve: (country, args)=>{
debugger
if (args.year){
country.getData({where: args});
} else {
country.getData();
}
}
}
});
module.exports = Country;

78
models/datum.js Normal file
View File

@@ -0,0 +1,78 @@
"use strict";
var Database = require("./../config/database");
class Datum {
static associate(){
var Country = require("./country");
this.sql.belongsTo(Country.sql, {foreignKey: "country_id", targetKey: "id", constraints: false});
}
}
Datum.sql = Database.sequelize.define('Datum', {
id: {
type: Database.Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true // Automatically gets converted to SERIAL for postgres
},
country_id: {
type: Database.Sequelize.INTEGER,
unique: "country_year",
references: {
model: "countries",
key: "id",
allowNull: false
}
},
year: {
type: Database.Sequelize.INTEGER,
unique: "country_year",
allowNull: false
},
population: Database.Sequelize.BIGINT,
gdp: Database.Sequelize.FLOAT,
total_emissions: Database.Sequelize.FLOAT,
energy_emissions: Database.Sequelize.FLOAT,
industrial_emissions: Database.Sequelize.FLOAT,
agriculture_emissions: Database.Sequelize.FLOAT,
waste_emissions: Database.Sequelize.FLOAT,
lucf_emissions: Database.Sequelize.FLOAT,
energy: Database.Sequelize.FLOAT
}, {tableName: "data"});
Datum.graphql = new GraphQLObjectType({
name: "Datum",
description: "A world country",
fields: ()=>{
year: {
type: new GraphQLNonNull(GraphQLString)
},
population: {
type: GraphQLInteger
},
gdp: {
type: GraphQLFloat
},
total_emissions: {
type: GraphQLFloat
},
energy_emissions: {
type: GraphQLFloat
},
industrial_emissions: {
type: GraphQLFloat
},
agriculture_emissions: {
type: GraphQLFloat
},
waste_emissions: {
type: GraphQLFloat
},
lucf_emissions: {
type: GraphQLFloat
}
}
});
module.exports = Datum;

49
models/house.js Normal file
View File

@@ -0,0 +1,49 @@
import {
GraphQLString,
GraphQLNonNull,
GraphQLObjectType
} from 'graphql';
import {
fromGlobalId,
globalIdField,
nodeDefinitions,
} from 'graphql-relay';
import Database from "./../config/database";
import PowerData from "./power_datum"
/**
* Define your own types here
*/
var House = Database.sequelize.define('House', {
id: {
type: Database.Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true // Automatically gets converted to SERIAL for postgres
},
name: Database.Sequelize.STRING
}, {
tableName: "houses",
instanceMethods: {
},
classMethods: {
associate: function(){
House.hasMany(PowerDatum, {as: 'PowerData'})
}
}
});
House.graphql_type = new GraphQLObjectType({
name: 'House',
description: 'A house',
fields: () => ({
id: globalIdField('House'),
name: GraphQLNonNull(GraphQLInt)
}),
interfaces: [nodeInterface],
});
export House;

53
models/power_datum.js Normal file
View File

@@ -0,0 +1,53 @@
import {
GraphQLFloat,
GraphQLInt,
GraphQLNonNull,
GraphQLObjectType
} from 'graphql';
import {
fromGlobalId,
globalIdField,
nodeDefinitions,
} from 'graphql-relay';
import Database from "./../config/database";
import PowerData from "./house"
/**
* Define your own types here
*/
var PowerDatum = Database.sequelize.define('Datum', {
id: {
type: Database.Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true // Automatically gets converted to SERIAL for postgres
},
time: Database.Sequelize.FLOAT,
power: Database.Sequelize.FLOAT
}, {
tableName: "power_data",
instanceMethods: {
},
classMethods: {
associate: function(){
PowerDatum.belongsTo(House);
}
}
});
PowerDatum.graphql_type = new GraphQLObjectType({
name: 'Power Datum',
description: 'A person who uses our app',
fields: () => ({
id: globalIdField('PowerDatum'),
time: GraphQLInt,
power: GraphQLFloat
}),
interfaces: [nodeInterface],
});
export PowerDatum;

47
npm-debug.log Normal file
View File

@@ -0,0 +1,47 @@
0 info it worked if it ends with ok
1 verbose cli [ '/home/eric/.nvm/v5.4.1/bin/node',
1 verbose cli '/home/eric/.nvm/v5.4.1/bin/npm',
1 verbose cli 'start' ]
2 info using npm@3.5.3
3 info using node@v5.4.1
4 verbose run-script [ 'prestart', 'start', 'poststart' ]
5 info lifecycle spike_proto@0.0.0~prestart: spike_proto@0.0.0
6 silly lifecycle spike_proto@0.0.0~prestart: no script for prestart, continuing
7 info lifecycle spike_proto@0.0.0~start: spike_proto@0.0.0
8 verbose lifecycle spike_proto@0.0.0~start: unsafe-perm in lifecycle true
9 verbose lifecycle spike_proto@0.0.0~start: PATH: /home/eric/.nvm/v5.4.1/lib/node_modules/npm/bin/node-gyp-bin:/home/eric/Code/spike_proto/node_modules/.bin:/home/eric/.nvm/v5.4.1/bin:/home/eric/.rvm/gems/ruby-1.9.3-p484@oroeco_dev/bin:/home/eric/.rvm/gems/ruby-1.9.3-p484@global/bin:/home/eric/.rvm/rubies/ruby-1.9.3-p484/bin:/home/eric/.rvm/bin:/home/eric/bin:/usr/local/heroku/bin:/home/eric/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/opt/lampp/bin
10 verbose lifecycle spike_proto@0.0.0~start: CWD: /home/eric/Code/spike_proto
11 silly lifecycle spike_proto@0.0.0~start: Args: [ '-c', 'babel-node ./app.js' ]
12 silly lifecycle spike_proto@0.0.0~start: Returned: code: 1 signal: null
13 info lifecycle spike_proto@0.0.0~start: Failed to exec start script
14 verbose stack Error: spike_proto@0.0.0 start: `babel-node ./app.js`
14 verbose stack Exit status 1
14 verbose stack at EventEmitter.<anonymous> (/home/eric/.nvm/v5.4.1/lib/node_modules/npm/lib/utils/lifecycle.js:232:16)
14 verbose stack at emitTwo (events.js:87:13)
14 verbose stack at EventEmitter.emit (events.js:172:7)
14 verbose stack at ChildProcess.<anonymous> (/home/eric/.nvm/v5.4.1/lib/node_modules/npm/lib/utils/spawn.js:24:14)
14 verbose stack at emitTwo (events.js:87:13)
14 verbose stack at ChildProcess.emit (events.js:172:7)
14 verbose stack at maybeClose (internal/child_process.js:821:16)
14 verbose stack at Process.ChildProcess._handle.onexit (internal/child_process.js:211:5)
15 verbose pkgid spike_proto@0.0.0
16 verbose cwd /home/eric/Code/spike_proto
17 error Linux 3.19.0-43-generic
18 error argv "/home/eric/.nvm/v5.4.1/bin/node" "/home/eric/.nvm/v5.4.1/bin/npm" "start"
19 error node v5.4.1
20 error npm v3.5.3
21 error code ELIFECYCLE
22 error spike_proto@0.0.0 start: `babel-node ./app.js`
22 error Exit status 1
23 error Failed at the spike_proto@0.0.0 start script 'babel-node ./app.js'.
23 error Make sure you have the latest version of node.js and npm installed.
23 error If you do, this is most likely a problem with the spike_proto package,
23 error not with npm itself.
23 error Tell the author that this fails on your system:
23 error babel-node ./app.js
23 error You can get information on how to open an issue for this project with:
23 error npm bugs spike_proto
23 error Or if that isn't available, you can get their info via:
23 error npm owner ls spike_proto
23 error There is likely additional logging output above.
24 verbose exit [ 1, true ]

59
package.json Normal file
View File

@@ -0,0 +1,59 @@
{
"name": "spike_proto",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "babel-node ./app.express.js",
"update-schema": "babel-node ./scripts/updateSchema.js"
},
"dependencies": {
"body-parser": "~1.12.0",
"cookie-parser": "~1.3.4",
"debug": "~2.1.1",
"jade": "~1.9.2",
"morgan": "~1.5.1",
"serve-favicon": "~2.2.0",
"connect-assets": "~4.7.0",
"connect-jade-static": "~0.2.2",
"node-forge": "~0.6.26",
"sequelize": "~3.15.1",
"pg": "~4.4.3",
"pg-hstore": "~2.3.2",
"fast-csv": "0.6.0",
"babel-core": "6.3.21",
"babel-loader": "6.2.0",
"babel-polyfill": "6.3.14",
"babel-preset-es2015": "6.3.13",
"babel-preset-react": "6.3.13",
"babel-preset-stage-0": "6.3.13",
"babel-relay-plugin": "0.6.0",
"babel-core": "6.3.21",
"babel-loader": "6.2.0",
"babel-polyfill": "6.3.14",
"babel-preset-es2015": "6.3.13",
"babel-preset-react": "6.3.13",
"babel-preset-stage-0": "6.3.13",
"babel-relay-plugin": "0.6.0",
"express": "4.13.3",
"express-graphql": "0.4.5",
"graphql": "0.4.14",
"graphql-relay": "0.3.6",
"react": "0.14.3",
"react-dom": "0.14.3",
"react-relay": "0.6.0",
"webpack": "1.12.9",
"webpack-dev-server": "1.14.0",
"jquery": "2.2.0",
"bootstrap": "3.3.6",
"d3": "3.5.12",
"font-awesome": "4.5.0",
"css-loader": "^0.15.5",
"style-loader": "^0.12.3",
"connect-assets":"~4.7.0",
"node-sass": "3.4.2"
},
"devDependencies": {
"gulp": "^3.9.0",
"babel-cli": "^6.3.17"
}
}

41
public/index2.html Normal file
View File

@@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/assets/css/vendor.css" rel="stylesheet" type="text/css">
<link href="/assets/css/application.css" rel="stylesheet" type="text/css">
<title>Spike Prototype</title>
</head>
<body>
<div id="spike_container">
<div id="spike_content">
<nav style="margin-bottom:0px;" class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar" class="navbar-toggle collapsed"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button><a href="/" class="navbar-brand">Spike</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="/">Spike</a></li>
</ul>
</div>
</div>
</nav>
<div id="root"></div>
</div>
<div id="spike_footer">
<div class="container">Footer</div>
</div>
</div>
</body>
<script type="text/javascript">
// Force `fetch` polyfill to workaround Chrome not displaying request body
// in developer tools for the native `fetch`.
self.fetch = null;
</script>
<script src="http://localhost:3000/webpack-dev-server.js"></script>
<script src="/assets/js/vendor.js"></script>
<script src="/assets/js/application.js"></script>
</html>

1
readme.md Normal file
View File

@@ -0,0 +1 @@
[See necessary examples](https://drive.google.com/drive/u/0/folders/0B6Ys-9_Te2cFNktOU3VwSzA1VWs)

15
relay/app.relay.js Normal file
View File

@@ -0,0 +1,15 @@
import 'babel-polyfill';
import App from './components/App';
import AppHomeRoute from './routes/AppHomeRoute';
import React from 'react';
import ReactDOM from 'react-dom';
import Relay from 'react-relay';
ReactDOM.render(
<Relay.RootContainer
Component={App}
route={new AppHomeRoute()}
/>,
document.getElementById('root')
);

34
relay/components/App.js Normal file
View File

@@ -0,0 +1,34 @@
import React from 'react';
import Relay from 'react-relay';
class App extends React.Component {
render() {
return (
<div>
<h1>Widget list</h1>
<ul>
{this.props.viewer.widgets.edges.map(edge =>
<li key={edge.node.id}>{edge.node.name} (ID: {edge.node.id})</li>
)}
</ul>
</div>
);
}
}
export default Relay.createContainer(App, {
fragments: {
viewer: () => Relay.QL`
fragment on User {
widgets(first: 10) {
edges {
node {
id,
name,
},
},
},
}
`,
},
});

View File

@@ -0,0 +1,12 @@
import Relay from 'react-relay';
export default class extends Relay.Route {
static queries = {
viewer: () => Relay.QL`
query {
viewer
}
`,
};
static routeName = 'AppHomeRoute';
}

30
routes/query.graphql Normal file
View File

@@ -0,0 +1,30 @@
query GetAllCountries {
countries {
id
name
}
}
query GetYearData {
data(year: $years, country_id: $country_ids){
...DatumFragment
}
}
query GetCountryData($id: Integer!) {
countries(id: $id){
data {
...DatumFragment
}
}
}
fragment DatumFragment on Datum {
year
population
gdp
total_emissions
energy_emissions
industrial_emissions
agriculture_emissions
waste_emissions
lucf_emissions
}

37
routes/shema.js Normal file
View File

@@ -0,0 +1,37 @@
var queryType = new GraphQLObjectType({
name: 'Query',
fields: () => ({
countries: {
type: new GraphQLList(Country.graphql),
args: {
id: {
type: new GraphQLNonNull(GraphQLInteger)
},
name: {
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: (root, args) => {
Country.sql.find(args)
}
},
data: {
type: new GraphQLList(Datum.graphql),
args: {
years: {
type: new GraphQLList(GraphQLInteger)
},
country_id: {
type: new GraphQLList(GraphQLInteger)
}
},
resolve: (root, args)=>{
Datum.findAll({where: args})
}
}
})
});
module.exports = new GraphQLSchema({
query: queryType
});

29
scripts/updateSchema.js Executable file
View File

@@ -0,0 +1,29 @@
#!/usr/bin/env babel-node --optional es7.asyncFunctions
import fs from 'fs';
import path from 'path';
import { Schema } from '../data/schema';
import { graphql } from 'graphql';
import { introspectionQuery, printSchema } from 'graphql/utilities';
// Save JSON of full schema introspection for Babel Relay Plugin to use
(async () => {
var result = await (graphql(Schema, introspectionQuery));
if (result.errors) {
console.error(
'ERROR introspecting schema: ',
JSON.stringify(result.errors, null, 2)
);
} else {
fs.writeFileSync(
path.join(__dirname, '../data/schema.json'),
JSON.stringify(result, null, 2)
);
}
})();
// Save user readable type system shorthand of schema
fs.writeFileSync(
path.join(__dirname, '../data/schema.graphql'),
printSchema(Schema)
);

6
views/error.jade Normal file
View File

@@ -0,0 +1,6 @@
extends layout
block content
h1= message
h2= error.status
pre #{error.stack}

3
views/index.jade Normal file
View File

@@ -0,0 +1,3 @@
extends layout
block content
div(id="root")

35
views/layout.jade Normal file
View File

@@ -0,0 +1,35 @@
doctype html
html
head
meta(charset='utf-8')
meta(http-equiv='content-type', content='text/html; charset=UTF-8')
meta(name='viewport', content='width=device-width, initial-scale=1')
!= css("vendor")
!= css("application")
title Spike Prototype
body
#spike_container
#spike_content
nav.navbar.navbar-default(style='margin-bottom:0px;')
.container
.navbar-header
button.navbar-toggle.collapsed(type='button', data-toggle='collapse', data-target='#navbar', aria-expanded='false', aria-controls='navbar')
span.sr-only Toggle navigation
span.icon-bar
span.icon-bar
span.icon-bar
a.navbar-brand(href='/') Spike
#navbar.collapse.navbar-collapse
ul.nav.navbar-nav.navbar-right
li
a(href='/') Spike
block content
#spike_footer
.container Footer
script(type='text/javascript').
// Force `fetch` polyfill to workaround Chrome not displaying request body
// in developer tools for the native `fetch`.
self.fetch = null;
script(src='http://localhost:3000/webpack-dev-server.js')
!= js("vendor")
script(src='/assets/js/application.js')