From 4242a5121e25b0002040e9a81a5a82ef3c4650a3 Mon Sep 17 00:00:00 2001 From: Gabriel Marcos Date: Sun, 15 Jul 2018 19:54:14 -0300 Subject: [PATCH] Create resolvers to model --- src/app.ts | 21 +++-- src/graphql/mutation.ts | 14 ++- src/graphql/query.ts | 9 +- .../resource/comment/comment.resovers.ts | 0 .../resource/comment/comment.schema.ts | 28 +++--- src/graphql/resource/post/post.resovers.ts | 42 +++++++++ src/graphql/resource/post/post.schema.ts | 21 +++-- src/graphql/resource/user/user.resolvers.ts | 88 +++++++++++++++++++ src/graphql/resource/user/user.schema.ts | 15 ++-- src/graphql/schema.ts | 16 ++-- src/interfaces/BaseModelInterface.ts | 2 +- src/interfaces/DbConnectionInterface.ts | 2 +- src/interfaces/ModelsInterface.ts | 6 +- src/models/CommentModel.ts | 4 +- src/models/PostModel.ts | 4 +- src/models/UserModel.ts | 9 +- src/utils/utils.ts | 2 +- 17 files changed, 219 insertions(+), 64 deletions(-) create mode 100644 src/graphql/resource/comment/comment.resovers.ts create mode 100644 src/graphql/resource/post/post.resovers.ts create mode 100644 src/graphql/resource/user/user.resolvers.ts diff --git a/src/app.ts b/src/app.ts index d036e2d..ba2dca3 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,6 +1,8 @@ import * as express from 'express' import * as graphqlHTTP from 'express-graphql' -import schema from './graphql/schema'; + +import db from './models' +import schema from './graphql/schema' class App { public express: express.Application @@ -11,10 +13,19 @@ class App { } private middleware(): void { - this.express.use('/graphql', graphqlHTTP({ - schema: schema, - graphiql: process.env.NODE_ENV === 'development' - })) + this.express.use('/graphql', + + (req, res, next) => { + req['context'] = {} + req['context'].db = db + next() + }, + graphqlHTTP((req) => ({ + schema: schema, + graphiql: process.env.NODE_ENV === 'development', + context: req['context'] + })) + ) } } diff --git a/src/graphql/mutation.ts b/src/graphql/mutation.ts index 09761e9..43dba48 100644 --- a/src/graphql/mutation.ts +++ b/src/graphql/mutation.ts @@ -1,15 +1,13 @@ +import { commentMutations } from './resource/comment/comment.schema' +import { postMutations } from './resource/post/post.schema' import { userMutations } from './resource/user/user.schema' -import { postMutation } from './resource/post/post.schema' -import { commentMutation } from './resource/comment/comment.schema'; - const Mutation = ` - type: Mutation( - ${ commentMutation } - ${ postMutation } + type Mutation { + ${ commentMutations } + ${ postMutations } ${ userMutations } - - ) + } ` export { diff --git a/src/graphql/query.ts b/src/graphql/query.ts index 3c30de8..52751d5 100644 --- a/src/graphql/query.ts +++ b/src/graphql/query.ts @@ -1,14 +1,13 @@ -import { userQueries } from './resource/user/user.schema' +import { commentQueries } from './resource/comment/comment.schema' import { postQueries } from './resource/post/post.schema' -import { commentQueries } from './resource/comment/comment.schema'; - +import { userQueries } from './resource/user/user.schema' const Query = ` - type: Query( + type Query { ${ commentQueries } ${ postQueries } ${ userQueries } - ) + } ` export { diff --git a/src/graphql/resource/comment/comment.resovers.ts b/src/graphql/resource/comment/comment.resovers.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/graphql/resource/comment/comment.schema.ts b/src/graphql/resource/comment/comment.schema.ts index 5f6801d..467cdfb 100644 --- a/src/graphql/resource/comment/comment.schema.ts +++ b/src/graphql/resource/comment/comment.schema.ts @@ -1,7 +1,8 @@ -const commentType = ` - type Post { +const commentTypes = ` + + type Comment { id: ID! - commnet: String! + comment: String! createdAt: String! updatedAt: String! user: User! @@ -10,20 +11,23 @@ const commentType = ` input CommentInput { comment: String! - post: Int!, - user: Int! + post: Int! } + ` + const commentQueries = ` - commentsByPost(post: ID!, first: Int, offset: Int): [ Comment! ]! + commentsByPost(postId: ID!, first: Int, offset: Int): [ Comment! ]! ` -const commentMutation = ` + +const commentMutations = ` createComment(input: CommentInput!): Comment - updatePost(id: ID!, input: CommentInput!): Comment - deletePost(id: ID!) + updateComment(id: ID!, input: CommentInput!): Comment + deleteComment(id: ID!): Boolean ` + export { - commentType, + commentTypes, commentQueries, - commentMutation -} \ No newline at end of file + commentMutations +} diff --git a/src/graphql/resource/post/post.resovers.ts b/src/graphql/resource/post/post.resovers.ts new file mode 100644 index 0000000..6249d94 --- /dev/null +++ b/src/graphql/resource/post/post.resovers.ts @@ -0,0 +1,42 @@ +import { GraphQLResolveInfo } from "graphql" + +import { DbConnection } from "../../../interfaces/DbConnectionInterface" +import { PostInterface } from "../../../models/PostModel"; + +export const postResolvers = { + + Post: { + + author:(post, args, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => { + return db.User.findById(post.get('author')) + }, + + comments:(post, {first = 10, offset = 0}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => { + return db.Comment + .findAll({ + where: { post: post.get('id') }, + limit: first, + offset: offset + }) + } + }, + + Query: { + posts: (parent, {first = 10, offset = 0}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => { + return db.Post + .findAll({ + limit: first, + offset: offset + }) + }, + + post: (parent, {id}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => { + return db.Post + .findById(id) + .then((post: PostInterface) => { + if (!post) throw new Error(`Post with id ${id} not found!`) + return post + }) + } + } +} \ No newline at end of file diff --git a/src/graphql/resource/post/post.schema.ts b/src/graphql/resource/post/post.schema.ts index afe5a33..fd6f420 100644 --- a/src/graphql/resource/post/post.schema.ts +++ b/src/graphql/resource/post/post.schema.ts @@ -1,34 +1,37 @@ const postTypes = ` + type Post { id: ID! title: String! content: String! - photo: String + photo: String! createdAt: String! - updatedAt: String! + updated: String! author: User! - comments: [ Comment! ] + comments: [ Comment! ]! } input PostInput { title: String! content: String! - photo: String - author: User! + photo: String! } + ` const postQueries = ` - posts(first: Int, offset: Int): [ Post! ] + posts(first: Int, offset: Int): [ Post! ]! post(id: ID!): Post ` -const postMutation = ` + +const postMutations = ` createPost(input: PostInput!): Post updatePost(id: ID!, input: PostInput!): Post - deletePost(id: ID!) + deletePost(id: ID!): Boolean ` + export { postTypes, postQueries, - postMutation + postMutations } \ No newline at end of file diff --git a/src/graphql/resource/user/user.resolvers.ts b/src/graphql/resource/user/user.resolvers.ts new file mode 100644 index 0000000..1a57102 --- /dev/null +++ b/src/graphql/resource/user/user.resolvers.ts @@ -0,0 +1,88 @@ +import { GraphQLResolveInfo } from "../../../../node_modules/@types/graphql" +import { Transaction } from "../../../../node_modules/@types/sequelize" + +import { DbConnection } from "../../../interfaces/DbConnectionInterface" +import { UserInstance } from "../../../models/UserModel" + +export const userResolvers = { + + User: { + posts: (user: UserInstance, {first = 10, offset = 0}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => { + return db.Post + .findAll({ + where: {author: user.get('id')}, + limit: first, + offset: offset + }) + } + }, + + Query: { + users: (parent, {first = 10, offset = 0}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => { + return db.User + .findAll({ + limit: first, + offset: offset + }) + }, + + user: (parent, {id}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => { + return db.User + .find(id) + .then((user: UserInstance) => { + if (!user) { + throw new Error(`User with ${id} not found!`) + return user + } + }) + } + }, + + Mutation: { + + createUser: (parent, {input}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => { + return db.sequelize.transaction((t: Transaction) => { + return db.User.create(input, {transaction: t}) + }) + }, + + updateUser: (parent, {id, input}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => { + id = parseInt(id) + return db.sequelize.transaction((t: Transaction) => { + return db.User + .findById(id) + .then((user: UserInstance) => { + if (!user) throw new Error(`User with ${id} not found!`) + return user.update(input, {transaction: t}) + }) + }) + }, + + updateUserPassword: (parent, {id, input}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => { + id = parseInt(id) + return db.sequelize.transaction((t: Transaction) => { + return db.User + .findById(id) + .then((user: UserInstance) => { + if (!user) throw new Error(`User with ${id} not found!`) + return user.update(input, {transaction: t}) + .then((user: UserInstance) => !!user) + }) + }) + }, + + deleteuser: (parent, {id}, {db}: {db: DbConnection}, info: GraphQLResolveInfo) => { + id = parseInt(id) + return db.sequelize.transaction((t: Transaction) => { + return db.User + .findById(id) + .then((user: UserInstance) => { + if (!user) throw new Error(`User with ${id} not found!`) + return user.destroy({transaction: t}) + .then(user => !!user) + }) + }) + } + } + +} \ No newline at end of file diff --git a/src/graphql/resource/user/user.schema.ts b/src/graphql/resource/user/user.schema.ts index 3499dc0..495e93a 100644 --- a/src/graphql/resource/user/user.schema.ts +++ b/src/graphql/resource/user/user.schema.ts @@ -1,4 +1,5 @@ const userTypes = ` + # User definition type type User { id: ID! @@ -7,6 +8,7 @@ const userTypes = ` photo: String createdAt: String! updatedAt: String! + posts(first: Int, offset: Int): [ Post! ]! } input UserCreateInput { @@ -27,15 +29,16 @@ const userTypes = ` ` const userQueries = ` - users(first: Int, offset: Int): [ User! ] - user(id: ID!): User + users(first: Int, offset: Int): [ User! ]! + user(id: ID!): User + currentUser: User ` const userMutations = ` - createUser(input: UserCreateInput()): User) - updateUser(id: ID!, input: UserUpdateInput): User - UserUpdatePassword(id: ID!, input: UserUpdatePasswordInput): Boolean - deleteUser(id: ID!): Boolean + createUser(input: UserCreateInput!): User + updateUser(input: UserUpdateInput!): User + updateUserPassword(input: UserUpdatePasswordInput!): Boolean + deleteUser: Boolean ` export { diff --git a/src/graphql/schema.ts b/src/graphql/schema.ts index 15f180d..2adbf3c 100644 --- a/src/graphql/schema.ts +++ b/src/graphql/schema.ts @@ -1,15 +1,15 @@ import { makeExecutableSchema } from 'graphql-tools' -import { Query } from "./query" -import { Mutation } from "./mutation" +import { Query } from './query' +import { Mutation } from './mutation' -import { postTypes } from './resource/post/post.schema'; -import { userTypes } from './resource/user/user.schema'; -import { commentType } from './resource/comment/comment.schema'; +import { commentTypes } from './resource/comment/comment.schema' +import { postTypes } from './resource/post/post.schema' +import { userTypes } from './resource/user/user.schema' const SchemaDefinition = ` - type: Schema { - query: Query, + type Schema { + query: Query mutation: Mutation } ` @@ -19,7 +19,7 @@ export default makeExecutableSchema({ SchemaDefinition, Query, Mutation, - commentType, + commentTypes, postTypes, userTypes ] diff --git a/src/interfaces/BaseModelInterface.ts b/src/interfaces/BaseModelInterface.ts index 2e50542..9c1e76b 100644 --- a/src/interfaces/BaseModelInterface.ts +++ b/src/interfaces/BaseModelInterface.ts @@ -1,4 +1,4 @@ -import { ModelsInterface } from "./ModelsInterface"; +import { ModelsInterface } from "./ModelsInterface" export interface BaseModelInterface { prototype? diff --git a/src/interfaces/DbConnectionInterface.ts b/src/interfaces/DbConnectionInterface.ts index 14b16ab..077d3fa 100644 --- a/src/interfaces/DbConnectionInterface.ts +++ b/src/interfaces/DbConnectionInterface.ts @@ -1,5 +1,5 @@ import * as Sequelize from 'sequelize' -import { ModelsInterface } from './ModelsInterface'; +import { ModelsInterface } from './ModelsInterface' export interface DbConnection extends ModelsInterface { sequelize: Sequelize.Sequelize diff --git a/src/interfaces/ModelsInterface.ts b/src/interfaces/ModelsInterface.ts index 614b457..3e268e8 100644 --- a/src/interfaces/ModelsInterface.ts +++ b/src/interfaces/ModelsInterface.ts @@ -1,6 +1,6 @@ -import { UserModel } from "../models/UserModel"; -import { PostModel } from "../models/PostModel"; -import { CommentModel } from "../models/CommentModel"; +import { UserModel } from "../models/UserModel" +import { PostModel } from "../models/PostModel" +import { CommentModel } from "../models/CommentModel" export interface ModelsInterface { User: UserModel diff --git a/src/models/CommentModel.ts b/src/models/CommentModel.ts index 88f9e75..4cc994e 100644 --- a/src/models/CommentModel.ts +++ b/src/models/CommentModel.ts @@ -1,6 +1,6 @@ import * as Sequelize from 'sequelize' -import { BaseModelInterface } from '../interfaces/BaseModelInterface'; -import { ModelsInterface } from '../interfaces/ModelsInterface'; +import { BaseModelInterface } from '../interfaces/BaseModelInterface' +import { ModelsInterface } from '../interfaces/ModelsInterface' export interface CommentAttributes { id?: string diff --git a/src/models/PostModel.ts b/src/models/PostModel.ts index 5420a26..e9290ee 100644 --- a/src/models/PostModel.ts +++ b/src/models/PostModel.ts @@ -1,6 +1,6 @@ import * as Sequelize from 'sequelize' -import { BaseModelInterface } from '../interfaces/BaseModelInterface'; -import { ModelsInterface } from '../interfaces/ModelsInterface'; +import { BaseModelInterface } from '../interfaces/BaseModelInterface' +import { ModelsInterface } from '../interfaces/ModelsInterface' export interface PostAttributes { id?: number diff --git a/src/models/UserModel.ts b/src/models/UserModel.ts index 508d14b..f93014f 100644 --- a/src/models/UserModel.ts +++ b/src/models/UserModel.ts @@ -2,7 +2,7 @@ import * as Sequelize from "sequelize" import { genSaltSync, hashSync, compareSync } from 'bcryptjs' import { BaseModelInterface } from "../interfaces/BaseModelInterface" -import { ModelsInterface } from "../interfaces/ModelsInterface"; +import { ModelsInterface } from "../interfaces/ModelsInterface" export interface UserAttributes { id?:number @@ -56,6 +56,13 @@ export default (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes): beforeCreate: (user: UserInstance, options: Sequelize.CreateOptions): void => { const salt = genSaltSync() user.password = hashSync(user.password, salt) + }, + + beforeUpdate: (user: UserInstance, options: Sequelize.CreateOptions): void => { + if (user.changed('password')) { + const salt = genSaltSync() + user.password = hashSync(user.password, salt) + } } } }) diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 8c1612f..0fec02d 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,5 +1,5 @@ import { Server } from "http" -import { AddressInfo } from "dgram"; +import { AddressInfo } from "dgram" export const normalizePort = (val: number | string): number | string | boolean => { let port: number = (typeof val === 'string') ? parseInt(val) : val