From 40d325a318261bf3d1706188b1509fa9cc51090e Mon Sep 17 00:00:00 2001 From: Fre Timmerman Date: Tue, 2 Feb 2021 11:34:34 +0100 Subject: [PATCH] done 2 --- package.json | 5 +++-- schema.gql | 23 +++++++++++++++++++---- src/data.js | 23 +++++++++++++++++++---- src/resolvers.js | 41 +++++++++++++++++++++++++++++++++++++---- src/resolvers.ts | 37 +++++++++++++++++++++++++++++++++---- src/typeDefs.js | 48 +++++++++++++++++++++++++++++++++++++++++++++--- src/typeDefs.ts | 29 +++++++++++++++++++++++++---- tsconfig.json | 3 ++- 8 files changed, 183 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index e3fbd58..f273480 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,10 @@ "graphql": "^15.5.0", "reflect-metadata": "^0.1.13", "type-graphql": "^1.1.1", - "uuid": "^3.3.2" + "uuid": "^3.3.2", + "yup": "^0.32.8" }, "devDependencies": { "tsc-watch": "^4.2.9" } -} \ No newline at end of file +} diff --git a/schema.gql b/schema.gql index 8dd1e45..a36a933 100644 --- a/schema.gql +++ b/schema.gql @@ -3,14 +3,29 @@ # !!! DO NOT MODIFY THIS FILE BY YOURSELF !!! # ----------------------------------------------- +type Mutation { + """Create a new store""" + createStore(input: StoreInput!): Store! +} + type Query { - """Get all the stores """ + """Get all the stores""" stores: [Store!]! } type Store { - id: ID! - - """The name of the store""" + city: String! + id: String! name: String! + number: Int! + postalCode: String! + street: String! +} + +input StoreInput { + city: String! + name: String! + number: Int! + postalCode: String! + street: String! } diff --git a/src/data.js b/src/data.js index ca400a1..214677b 100644 --- a/src/data.js +++ b/src/data.js @@ -1,18 +1,33 @@ -import * as uuid from 'uuid'; +import uuid from 'uuid'; const stores = [ { + city: 'Aalst', id: 'cc406ed9-fc02-4185-b073-8c12b61b5c79', name: 'Den Olijfboom', + number: 38, + postalCode: '9300', + street: 'Molenstraat', }, { + city: 'Aalst', id: '5f2919aa-333a-4745-8166-3002ab30de0e', - name: 'Pizza Talia' + name: 'Pizza Talia', + number: 147, + postalCode: '9300', + street: 'Sint Jobstraat', } ]; -export function createStore({ name }) { - const newStore = { id: uuid(), name }; +export function createStore({ city, name, number, postalCode, street }) { + const newStore = { + city, + id: uuid(), + name, + number, + postalCode, + street, + }; stores.push(newStore); return newStore; } diff --git a/src/resolvers.js b/src/resolvers.js index 7753146..12d032f 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -7,10 +7,24 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; +var __param = (this && this.__param) || function (paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +}; import "reflect-metadata"; -import { Resolver, Query } from "type-graphql"; -import { Store } from "./typeDefs.js"; -import { getStores } from "./data.js"; +import { Resolver, Query, Mutation, Arg } from "type-graphql"; +import { Store, StoreInput } from "./typeDefs.js"; +import { createStore, getStores } from "./data.js"; +import * as yup from 'yup'; +import { UserInputError } from "apollo-server"; +// define input validations +const createStoreSchema = yup.object() + .shape({ + city: yup.string().max(255).required(), + name: yup.string().max(255).required(), + number: yup.number().required().positive().integer(), + postalCode: yup.string().required().max(10), + street: yup.string().required().max(255), +}); let StoreResolver = class StoreResolver { constructor() { this.storeCollection = getStores(); @@ -18,13 +32,32 @@ let StoreResolver = class StoreResolver { async stores() { return await this.storeCollection; } + async createStore(input) { + // check validity + return await createStoreSchema + .validate(input) + .then(validData => { + // put in db with data.js and return the value to grapqhl + return createStore(validData); + }) + .catch(err => { + return new UserInputError('Invalid input', { validationErrors: err.errors }); + }); + } }; __decorate([ - Query(returns => [Store], { description: "Get all the stores " }), + Query(returns => [Store], { description: "Get all the stores" }), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], StoreResolver.prototype, "stores", null); +__decorate([ + Mutation(() => Store, { description: "Create a new store" }), + __param(0, Arg("input")), + __metadata("design:type", Function), + __metadata("design:paramtypes", [StoreInput]), + __metadata("design:returntype", Promise) +], StoreResolver.prototype, "createStore", null); StoreResolver = __decorate([ Resolver() ], StoreResolver); diff --git a/src/resolvers.ts b/src/resolvers.ts index 125227d..f37789c 100644 --- a/src/resolvers.ts +++ b/src/resolvers.ts @@ -1,14 +1,43 @@ import "reflect-metadata"; -import { Resolver, Query } from "type-graphql"; -import { Store } from "./typeDefs.js"; -import { getStores } from "./data.js"; +import { Resolver, Query, Mutation, Arg } from "type-graphql"; +import { Store, StoreInput } from "./typeDefs.js"; +import { createStore, getStores } from "./data.js"; +import * as yup from 'yup'; +import { UserInputError } from "apollo-server"; + +// define input validations +const createStoreSchema = yup.object() + .shape({ + city: yup.string().max(255).required(), + name: yup.string().max(255).required(), + number: yup.number().required().positive().integer(), + postalCode: yup.string().required().max(10), + street: yup.string().required().max(255), + }); + @Resolver() export class StoreResolver { private storeCollection: Store[] = getStores(); - @Query(returns => [Store], { description: "Get all the stores " }) + @Query(returns => [Store], { description: "Get all the stores" }) async stores(): Promise { return await this.storeCollection; } + + @Mutation(() => Store, { description: "Create a new store" }) + async createStore(@Arg("input") input: StoreInput) { + // check validity + return await createStoreSchema + .validate(input) + .then(validData => { + // put in db with data.js and return the value to grapqhl + return createStore(validData); + }) + .catch(err => { + return new UserInputError('Invalid input', { validationErrors: err.errors }); + }); + + } + } diff --git a/src/typeDefs.js b/src/typeDefs.js index 4619400..11e624a 100644 --- a/src/typeDefs.js +++ b/src/typeDefs.js @@ -10,18 +10,60 @@ var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; import "reflect-metadata"; -import { ObjectType, Field, ID } from "type-graphql"; +import { ObjectType, Field, InputType, Int } from "type-graphql"; let Store = class Store { }; __decorate([ - Field(() => ID), + Field(), __metadata("design:type", String) ], Store.prototype, "id", void 0); __decorate([ - Field(() => String, { description: "The name of the store" }), + Field(), __metadata("design:type", String) ], Store.prototype, "name", void 0); +__decorate([ + Field(), + __metadata("design:type", String) +], Store.prototype, "city", void 0); +__decorate([ + Field(type => Int), + __metadata("design:type", Number) +], Store.prototype, "number", void 0); +__decorate([ + Field(), + __metadata("design:type", String) +], Store.prototype, "postalCode", void 0); +__decorate([ + Field(), + __metadata("design:type", String) +], Store.prototype, "street", void 0); Store = __decorate([ ObjectType() ], Store); export { Store }; +let StoreInput = class StoreInput { +}; +__decorate([ + Field(), + __metadata("design:type", String) +], StoreInput.prototype, "name", void 0); +__decorate([ + Field(), + __metadata("design:type", String) +], StoreInput.prototype, "city", void 0); +__decorate([ + Field(type => Int), + __metadata("design:type", Number) +], StoreInput.prototype, "number", void 0); +__decorate([ + Field(), + __metadata("design:type", String) +], StoreInput.prototype, "postalCode", void 0); +__decorate([ + Field(), + __metadata("design:type", String) +], StoreInput.prototype, "street", void 0); +StoreInput = __decorate([ + InputType() +], StoreInput); +export { StoreInput }; diff --git a/src/typeDefs.ts b/src/typeDefs.ts index 2db0d04..d3ef753 100644 --- a/src/typeDefs.ts +++ b/src/typeDefs.ts @@ -2,14 +2,35 @@ // which ways the data can be fetched from the GraphQL server. import "reflect-metadata"; -import { ObjectType, Field, ID } from "type-graphql"; +import { ObjectType, Field, ID, InputType, Int } from "type-graphql"; +import { number } from "yup/lib/locale"; @ObjectType() export class Store { - @Field(() => ID) + @Field() id: string; - - @Field(() => String, { description: "The name of the store" }) + @Field() name: string; + @Field() + city: string; + @Field(type => Int) + number: number; + @Field() + postalCode: string + @Field() + street: string +} +@InputType() +export class StoreInput { + @Field() + name: string; + @Field() + city: string; + @Field(type => Int) + number: number; + @Field() + postalCode: string + @Field() + street: string } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 7ede0a2..80c8404 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,7 @@ ], "moduleResolution": "node", "experimentalDecorators": true, - "emitDecoratorMetadata": true + "emitDecoratorMetadata": true, + "allowSyntheticDefaultImports": true } } \ No newline at end of file