├── .gitignore ├── .env.example ├── README.md ├── config └── config.js ├── models ├── hobbies.js ├── student.js └── index.js ├── server.js ├── package.json ├── schema ├── typeDefs.js └── resolvers.js └── migrations ├── 20190327125607-create-student.js └── 20190327130528-create-hobbies.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | POSTGRES_DB=postgres_link 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## GraphQL Sequelize Starter 2 | -------------------------------------------------------------------------------- /config/config.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | 3 | const environment = { 4 | development: { 5 | password: null, 6 | url: process.env.POSTGRES_DB, 7 | dialect: "postgres" 8 | } 9 | } 10 | 11 | module.exports = environment 12 | -------------------------------------------------------------------------------- /models/hobbies.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = (sequelize, DataTypes) => { 3 | const Hobbies = sequelize.define('Hobbies', { 4 | title: DataTypes.STRING 5 | }, {}); 6 | Hobbies.associate = function(models) { 7 | Hobbies.belongsTo(models.Student, { 8 | foreignKey: 'studentId' }) 9 | }; 10 | return Hobbies; 11 | }; 12 | -------------------------------------------------------------------------------- /models/student.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = (sequelize, DataTypes) => { 3 | const Student = sequelize.define('Student', { 4 | firstName: DataTypes.STRING, 5 | email: DataTypes.STRING 6 | }, {}); 7 | Student.associate = function(models) { 8 | Student.hasMany(models.Hobbies) 9 | }; 10 | return Student; 11 | }; 12 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const { ApolloServer } = require('apollo-server-express'); 3 | 4 | const typeDefs = require('./schema/typeDefs') 5 | const resolvers = require('./schema/resolvers') 6 | const models = require('./models') 7 | 8 | 9 | const server = new ApolloServer({ typeDefs, resolvers, context: { models } }); 10 | 11 | const app = express(); 12 | server.applyMiddleware({ app }); 13 | 14 | models.sequelize.authenticate(); 15 | models.sequelize.sync(); 16 | 17 | app.listen({ port: 4000 }, () => 18 | console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`) 19 | ); 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Hack", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "dependencies": { 7 | "apollo-server-express": "^2.14.2", 8 | "dotenv": "^8.0.0", 9 | "express": "^4.16.4", 10 | "graphql": "^14.2.0", 11 | "pg": "^8.0.0", 12 | "pg-hstore": "^2.3.2", 13 | "sequelize": "^5.15.1", 14 | "sequelize-cli": "^5.4.0" 15 | }, 16 | "devDependencies": {}, 17 | "scripts": { 18 | "test": "echo \"Error: no test specified\" && exit 1", 19 | "start": "node server.js" 20 | }, 21 | "keywords": [], 22 | "author": "", 23 | "license": "ISC" 24 | } 25 | -------------------------------------------------------------------------------- /schema/typeDefs.js: -------------------------------------------------------------------------------- 1 | const { gql } = require('apollo-server-express') 2 | 3 | const typeDefs = gql` 4 | 5 | type Student { 6 | id: Int! 7 | firstName: String! 8 | email: String! 9 | hobbies: [Hobbies!]! 10 | } 11 | 12 | type Hobbies { 13 | id: Int! 14 | title: String! 15 | student: Student! 16 | } 17 | 18 | type Query { 19 | getStudent(id: Int!): Student 20 | getAllStudents: [Student!]! 21 | getHobbies(id: Int!): Hobbies 22 | } 23 | 24 | type Mutation { 25 | createStudent(firstName: String!, email: String!): Student! 26 | createHobbies(studentId: Int!, title: String!): Hobbies! 27 | } 28 | ` 29 | 30 | module.exports = typeDefs 31 | -------------------------------------------------------------------------------- /migrations/20190327125607-create-student.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = { 3 | up: (queryInterface, Sequelize) => { 4 | return queryInterface.createTable('Students', { 5 | id: { 6 | allowNull: false, 7 | autoIncrement: true, 8 | primaryKey: true, 9 | type: Sequelize.INTEGER 10 | }, 11 | firstName: { 12 | type: Sequelize.STRING 13 | }, 14 | email: { 15 | type: Sequelize.STRING 16 | }, 17 | createdAt: { 18 | allowNull: false, 19 | type: Sequelize.DATE 20 | }, 21 | updatedAt: { 22 | allowNull: false, 23 | type: Sequelize.DATE 24 | } 25 | }); 26 | }, 27 | down: (queryInterface, Sequelize) => { 28 | return queryInterface.dropTable('Students'); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /migrations/20190327130528-create-hobbies.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = { 3 | up: (queryInterface, Sequelize) => { 4 | return queryInterface.createTable('Hobbies', { 5 | id: { 6 | allowNull: false, 7 | autoIncrement: true, 8 | primaryKey: true, 9 | type: Sequelize.INTEGER 10 | }, 11 | StudentId: { 12 | type: Sequelize.INTEGER, 13 | allowNull: false, 14 | references: { 15 | model: 'Student', // name of Target model 16 | key: 'id', // key in Target model that we're referencing 17 | }, 18 | }, 19 | title: { 20 | type: Sequelize.STRING 21 | }, 22 | createdAt: { 23 | allowNull: false, 24 | type: Sequelize.DATE 25 | }, 26 | updatedAt: { 27 | allowNull: false, 28 | type: Sequelize.DATE 29 | } 30 | }); 31 | }, 32 | down: (queryInterface, Sequelize) => { 33 | return queryInterface.dropTable('Hobbies'); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /schema/resolvers.js: -------------------------------------------------------------------------------- 1 | const resolvers = { 2 | Query: { 3 | async getStudent(root, { id }, { models }) { 4 | return models.Student.findByPk(id) 5 | }, 6 | async getAllStudents(root, args, { models }) { 7 | return models.Student.findAll() 8 | }, 9 | async getHobbies(root, { id }, { models }) { 10 | return await models.Hobbies.findByPk(id) 11 | } 12 | }, 13 | Mutation: { 14 | async createStudent(root, { firstName, email }, { models }) { 15 | return models.Student.create({ firstName, email }) 16 | }, 17 | async createHobbies(root, { studentId, title }, { models }) { 18 | return models.Hobbies.create({ studentId, title }) 19 | }, 20 | }, 21 | Student: { 22 | async hobbies(hobbies) { 23 | return hobbies.getHobbies() 24 | } 25 | }, 26 | Hobbies: { 27 | async student(student) { 28 | return student.getStudent() 29 | } 30 | }, 31 | 32 | } 33 | 34 | module.exports = resolvers 35 | -------------------------------------------------------------------------------- /models/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const Sequelize = require('sequelize'); 6 | const basename = path.basename(__filename); 7 | const env = process.env.NODE_ENV || 'development'; 8 | const config = require(__dirname + '/../config/config.js')[env]; 9 | const db = {}; 10 | 11 | 12 | let sequelize; 13 | if (config.use_env_variable) { 14 | sequelize = new Sequelize(process.env[config.use_env_variable], config); 15 | } else { 16 | sequelize = new Sequelize(config.url); 17 | } 18 | 19 | fs 20 | .readdirSync(__dirname) 21 | .filter(file => { 22 | return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); 23 | }) 24 | .forEach(file => { 25 | const model = sequelize['import'](path.join(__dirname, file)); 26 | db[model.name] = model; 27 | }); 28 | 29 | Object.keys(db).forEach(modelName => { 30 | if (db[modelName].associate) { 31 | db[modelName].associate(db); 32 | } 33 | }); 34 | 35 | db.sequelize = sequelize; 36 | db.Sequelize = Sequelize; 37 | 38 | module.exports = db; 39 | --------------------------------------------------------------------------------