Skip to content

Commit

Permalink
Add database migrations
Browse files Browse the repository at this point in the history
  • Loading branch information
koistya committed Feb 27, 2018
1 parent 29b4a91 commit 8ef3ca5
Show file tree
Hide file tree
Showing 14 changed files with 790 additions and 632 deletions.
8 changes: 5 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
# Javascript Node CircleCI 2.0 configuration file
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
# Check https://circleci.com/docs/2.0/ for more details

version: 2

jobs:
build:
# https://circleci.com/docs/2.0/configuration-reference/#docker
docker:
- image: circleci/node:8.9.3
steps:
- checkout
- restore_cache:
key: yarn-v1-{{ checksum "yarn.lock" }}
key: yarn-v1-
keys:
- yarn-v1-{{ checksum "yarn.lock" }}
- yarn-v1-
- run:
name: Install NPM modules
command: yarn
Expand Down
19 changes: 11 additions & 8 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@

# For more information about the properties used in
# this file, please see the EditorConfig documentation:
# http://editorconfig.org/
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# http://editorconfig.org

root = true

[*]
charset = utf-8
end_of_line = lf
indent_size = 2

# Change these settings to your own preference
indent_style = space
insert_final_newline = true
indent_size = 2

# We recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false
12 changes: 11 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@

FIREBASE_CREDENTIALS=

# Firebase Config for the client-side app

# Firebase config for the client-side app

REACT_APP_FIREBASE={"apiKey":"AIzaSyAsuqpqt29-TIwBAu01Nbt5QnC3FIKO4A4","authDomain":"react-firebase-graphql.firebaseapp.com","databaseURL":"https://react-firebase-graphql.firebaseio.com","projectId":"react-firebase-graphql","storageBucket":"react-firebase-graphql.appspot.com","messagingSenderId":"564620986275"}


# PostgreSQL settings

PGHOST=localhost
PGUSER=postgres
PGDATABASE=app
PGPASSWORD=
PGPORT=5432
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ This project was bootstraped with [React Starter Kit for Firebase][rfs] by [Kria
### Tech Stack

* [Create React App][cra] for development and test infrastructure (see [user guide][cradocs])
* [Firestore][firestore] and/or [Cloud SQL][cloudsql] (PostgreSQL) hosted database service
* [GraphQL][gqljs] and [Relay][relay] for declarative data fetching and maximum performance
* [Material UI][mui] to reduce development time by integrating Google's [Material Design][material]
* [Styled Components][sc] for component friendly CSS styles ([docs][scdocs])
Expand Down Expand Up @@ -86,6 +87,14 @@ Then open [http://localhost:3000/](http://localhost:3000/) to see your app.<br>

<p align='center'><img src='https://camo.githubusercontent.com/506a5a0a33aebed2bf0d24d3999af7f582b31808/687474703a2f2f692e696d6775722e636f6d2f616d794e66434e2e706e67' width='600' alt='npm start'></p>

### How to Migrate Database Schema

```bash
$ yarn db-change # Create a new database migration file
$ yarn db-migrate # Migrate database to the latest version
$ yarn db-rollback # Rollback the latest migration
```

### How to Test

```bash
Expand Down Expand Up @@ -160,6 +169,8 @@ and [contributors](https://github.com/kriasoft/react-firebase-starter/graphs/con
[telegram]: https://t.me/ReactStarter
[cra]: https://github.com/facebook/create-react-app
[cradocs]: https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md
[firestore]: https://cloud.google.com/firestore/
[cloudsql]: https://cloud.google.com/sql/
[gqljs]: http://graphql.org/graphql-js/
[relay]: http://facebook.github.io/relay/
[mui]: https://material-ui-next.com/
Expand Down
13 changes: 13 additions & 0 deletions knexfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* React Starter Kit for Firebase
* https://github.com/kriasoft/react-firebase-starter
* Copyright (c) 2015-present Kriasoft | MIT License
*/

require('dotenv').config();

// Knex configuration
// http://knexjs.org/#knexfile
module.exports = {
client: 'pg',
};
54 changes: 54 additions & 0 deletions migrations/20180101000000_initial.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* React Starter Kit for Firebase
* https://github.com/kriasoft/react-firebase-starter
* Copyright (c) 2015-present Kriasoft | MIT License
*/

/* prettier-ignore */

exports.up = async db => {
await db.schema.createTable('users', table => {
table.uuid('id').notNullable().defaultTo(db.raw('uuid_generate_v4()')).primary();
table.string('display_name', 100);
table.string('photo_url', 200);
table.timestamps(false, true);
});

await db.schema.createTable('stories', table => {
table.uuid('id').notNullable().defaultTo(db.raw('uuid_generate_v4()')).primary();
table.uuid('author_id').notNullable().references('id').inTable('users').onDelete('CASCADE').onUpdate('CASCADE');
table.string('title', 80).notNullable();
table.string('url', 200);
table.text('text');
table.timestamps(false, true);
});

await db.schema.createTable('story_points', table => {
table.uuid('story_id').references('id').inTable('stories').onDelete('CASCADE').onUpdate('CASCADE');
table.uuid('user_id').notNullable().references('id').inTable('users').onDelete('CASCADE').onUpdate('CASCADE');
table.primary(['story_id', 'user_id']);
});

await db.schema.createTable('comments', table => {
table.uuid('id').notNullable().defaultTo(db.raw('uuid_generate_v4()')).primary();
table.uuid('story_id').notNullable().references('id').inTable('stories').onDelete('CASCADE').onUpdate('CASCADE');
table.uuid('parent_id').references('id').inTable('comments').onDelete('CASCADE').onUpdate('CASCADE');
table.uuid('author_id').notNullable().references('id').inTable('users').onDelete('CASCADE').onUpdate('CASCADE');
table.text('text');
table.timestamps(false, true);
});

await db.schema.createTable('comment_points', table => {
table.uuid('comment_id').references('id').inTable('comments').onDelete('CASCADE').onUpdate('CASCADE');
table.uuid('user_id').notNullable().references('id').inTable('users').onDelete('CASCADE').onUpdate('CASCADE');
table.primary(['comment_id', 'user_id']);
});
};

exports.down = async db => {
await db.schema.dropTableIfExists('comment_points');
await db.schema.dropTableIfExists('comments');
await db.schema.dropTableIfExists('story_points');
await db.schema.dropTableIfExists('stories');
await db.schema.dropTableIfExists('users');
};
24 changes: 16 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
"dependencies": {
"@babel/polyfill": "^7.0.0-beta.40",
"@babel/runtime": "^7.0.0-beta.40",
"@firebase/app": "^0.1.9",
"@firebase/auth": "^0.3.3",
"@firebase/firestore": "^0.3.3",
"@firebase/app": "^0.1.10",
"@firebase/auth": "^0.3.4",
"@firebase/firestore": "^0.3.4",
"body-parser": "^1.18.2",
"classnames": "^2.2.5",
"cookie": "^0.3.1",
Expand All @@ -35,8 +35,10 @@
"graphql-relay": "^0.5.4",
"history": "^4.7.2",
"idx": "^2.2.0",
"material-ui": "1.0.0-beta.34",
"prop-types": "^15.6.0",
"knex": "^0.14.4",
"material-ui": "1.0.0-beta.35",
"pg": "^7.4.1",
"prop-types": "^15.6.1",
"query-string": "^5.1.0",
"raw-loader": "^0.5.1",
"react": "^16.2.0",
Expand All @@ -49,20 +51,22 @@
"validator": "^9.4.1"
},
"devDependencies": {
"@babel/register": "^7.0.0-beta.40",
"babel-plugin-relay": "^1.5.0",
"babel-plugin-styled-components": "^1.5.0",
"chai": "^4.1.2",
"dotenv": "^5.0.1",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-flowtype": "^2.45.0",
"eslint-plugin-flowtype": "^2.46.1",
"eslint-plugin-prettier": "^2.6.0",
"flow-bin": "^0.66.0",
"gh-pages": "^1.1.0",
"husky": "^0.15.0-rc.8",
"lint-staged": "^7.0.0",
"prettier": "^1.10.2",
"prettier": "^1.11.0",
"react-app-tools": "2.0.0-beta.10",
"relay-compiler": "^1.5.0",
"stylelint": "^9.1.0",
"stylelint": "^9.1.1",
"stylelint-config-primer": "^2.2.4",
"stylelint-config-standard": "^18.1.0",
"stylelint-config-styled-components-processor": "^0.1.1",
Expand All @@ -80,13 +84,17 @@
]
},
"scripts": {
"update-schema": "node ./scripts/update-schema",
"relay": "relay-compiler --src ./src --schema ./src/schema.graphql --include \"**/*.js\"",
"start": "react-app start",
"build": "react-app build",
"test": "react-app test --env=jsdom",
"lint": "eslint --ignore-path .gitignore --ignore-pattern \"!**/.*\" . && stylelint \"src/**/*.js\"",
"fix": "eslint --ignore-path .gitignore --ignore-pattern \"!**/.*\" --fix .",
"precommit": "lint-staged",
"db-change": "knex migrate:make",
"db-migrate": "knex migrate:latest",
"db-rollback": "knex migrate:rollback",
"deploy": "yarn install && yarn build && firebase use dev && firebase deploy",
"deploy-prod": "yarn install && yarn build && firebase use prod && firebase deploy"
}
Expand Down
25 changes: 25 additions & 0 deletions scripts/update-schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* React Starter Kit for Firebase
* https://github.com/kriasoft/react-firebase-starter
* Copyright (c) 2015-present Kriasoft | MIT License
*/

'use script';

process.env.NODE_ENV = 'test';

require('@babel/register')({
babelrc: false,
presets: [require.resolve('babel-preset-react-app')],
});

const fs = require('fs');
const path = require('path');
const graphql = require('graphql');
const schema = require('../src/graphql/schema').default;

fs.writeFileSync(
path.resolve(__dirname, '../src/schema.graphql'),
graphql.printSchema(schema, { commentDescriptions: true }),
'utf8',
);
2 changes: 1 addition & 1 deletion src/components/AppToolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Avatar from 'material-ui/Avatar/Avatar';
import Menu, { MenuItem } from 'material-ui/Menu';
import styled from 'styled-components';

import auth from '../../auth';
import auth from '../auth';
import Link from './Link';
import LoginDialog from './LoginDialog';

Expand Down
1 change: 1 addition & 0 deletions src/components/LoginDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class LoginDialog extends React.Component {
<DialogContent>
<Button
color="primary"
variant="raised"
disabled={this.state.loading}
onClick={this.signInWithFacebook}
>
Expand Down
8 changes: 4 additions & 4 deletions src/graphql/Context.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

/* @flow */

import DataLoader from './DataLoader';
import type { Request } from 'express';
import { auth } from 'firebase-admin';

import auth from './auth';
import DataLoader from './DataLoader';
import { UnauthorizedError } from './errors';
import type { Request } from 'express';

class Context {
constructor(req: Request) {
Expand All @@ -22,7 +22,7 @@ class Context {
}

userById = new DataLoader(keys =>
Promise.all(keys.map(key => auth.getUser(key))),
Promise.all(keys.map(key => auth().getUser(key))),
);

signIn(token) {
Expand Down
24 changes: 0 additions & 24 deletions src/graphql/auth.js

This file was deleted.

6 changes: 3 additions & 3 deletions src/graphql/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import fs from 'fs';
import path from 'path';
import cookie from 'cookie';
import expressGraphQL from 'express-graphql';
import { auth } from 'firebase-admin';
import { Router } from 'express';
import { printSchema } from 'graphql';

import auth from './auth';
import schema from './schema';
import Context from './Context';

Expand All @@ -38,9 +38,9 @@ async function authentication(req, res, next) {
const { __session: token } = req.headers.cookie
? cookie.parse(req.headers.cookie)
: {};
req.user = token ? await auth.verifyIdToken(token) : null;
req.user = token ? await auth().verifyIdToken(token) : null;
req.signIn = async token => {
const user = await auth.verifyIdToken(token);
const user = await auth().verifyIdToken(token);
if (user) {
res.cookie(sessionKey, token, sessionOptions);
}
Expand Down
Loading

0 comments on commit 8ef3ca5

Please sign in to comment.