From 54b2e99fd22c381c12ecf409d026c7a4dfe46f70 Mon Sep 17 00:00:00 2001 From: Fre Timmerman Date: Tue, 2 Feb 2021 15:08:42 +0100 Subject: [PATCH] done 3 --- schema.gql | 37 ++++++++++++++++++++++++------------- src/data.js | 44 +++++++++++++++++++++++++++++++++++++++++++- src/index.js | 1 + src/resolvers.js | 48 +++++++++++++++++++++++++++++++++++++++--------- src/resolvers.ts | 40 +++++++++++++++++++++++++++++++--------- src/typeDefs.js | 28 +++++++++++++++++++++++++++- src/typeDefs.ts | 17 +++++++++++++++-- 7 files changed, 180 insertions(+), 35 deletions(-) diff --git a/schema.gql b/schema.gql index a36a933..1d64a07 100644 --- a/schema.gql +++ b/schema.gql @@ -5,27 +5,38 @@ type Mutation { """Create a new store""" - createStore(input: StoreInput!): Store! + createStore(input: StoreInput): Store +} + +type Product { + description: String + id: String + name: String + price: Float } type Query { + """Get a specific store""" + store(id: String): Store + """Get all the stores""" - stores: [Store!]! + stores: [Store] } type Store { - city: String! - id: String! - name: String! - number: Int! - postalCode: String! - street: String! + city: String + id: String + name: String + number: Int + postalCode: String + products: [Product] + street: String } input StoreInput { - city: String! - name: String! - number: Int! - postalCode: String! - street: String! + city: String + name: String + number: Int + postalCode: String + street: String } diff --git a/src/data.js b/src/data.js index 214677b..18fcb66 100644 --- a/src/data.js +++ b/src/data.js @@ -19,6 +19,39 @@ const stores = [ } ]; +const products = [{ + description: 'Een broodje om u tegen te zeggen. Lekker, lekker, lekker!', + id: '9e3de707-8e96-45c8-8c1a-75d79fe74768', + name: 'Scampi Manis', + price: 5, + storeId: 'cc406ed9-fc02-4185-b073-8c12b61b5c79', +}, { + description: 'Eentje met kaas en fricandon, voor den groten honger.', + id: '1535f2a6-4341-4db0-a9c8-455c2347dcaf', + name: 'Gitaar', + price: 5, + storeId: 'cc406ed9-fc02-4185-b073-8c12b61b5c79', +}, { + description: 'Tomatensaus, kaas, ham, salami, champignons, paprika', + id: '5bb3fbcc-7ec2-44fe-a04b-a0251cecf1e6', + name: '4 Seizoenen Large', + price: 17, + storeId: '5f2919aa-333a-4745-8166-3002ab30de0e', +}, { + description: 'Bolognaisesaus, kaas, paprika, ham, salami, champignons', + id: '037e74f6-ae73-47a3-9acf-d1de0cdcd565', + name: 'Calzone Large', + price: 17, + storeId: '5f2919aa-333a-4745-8166-3002ab30de0e', +}, { + description: 'Tomatensaus, pepperoni, rode ui, paprika gehakt, jalapenos', + id: 'e8619184-2e86-4db5-b8ba-596720006a0f', + name: 'Hot \'n Spicy', + price: 20, + storeId: '5f2919aa-333a-4745-8166-3002ab30de0e', +}]; + + export function createStore({ city, name, number, postalCode, street }) { const newStore = { city, @@ -34,4 +67,13 @@ export function createStore({ city, name, number, postalCode, street }) { export function getStores() { return stores; -} \ No newline at end of file +} + +export function getStore(storeId) { + return stores.find(store => store.id === storeId); +} + +export function getStoreProducts(storeId) { + console.log(storeId); + return products.filter(prod => prod.storeId === storeId) +} \ No newline at end of file diff --git a/src/index.js b/src/index.js index ff05f4b..49551f1 100644 --- a/src/index.js +++ b/src/index.js @@ -30,6 +30,7 @@ import { StoreResolver } from './resolvers.js'; // create the schema using TypeGraphQL, pass the resolver const schema = await buildSchema({ resolvers: [StoreResolver], + nullableByDefault: true, emitSchemaFile: path.resolve(".", "schema.gql"), }); diff --git a/src/resolvers.js b/src/resolvers.js index 12d032f..55b20b0 100644 --- a/src/resolvers.js +++ b/src/resolvers.js @@ -11,9 +11,9 @@ var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; import "reflect-metadata"; -import { Resolver, Query, Mutation, Arg } from "type-graphql"; -import { Store, StoreInput } from "./typeDefs.js"; -import { createStore, getStores } from "./data.js"; +import { Resolver, Query, Mutation, Arg, FieldResolver, Root } from "type-graphql"; +import { Store, StoreInput, Product } from "./typeDefs.js"; +import { createStore, getStores, getStore, getStoreProducts } from "./data.js"; import * as yup from 'yup'; import { UserInputError } from "apollo-server"; // define input validations @@ -25,12 +25,28 @@ const createStoreSchema = yup.object() postalCode: yup.string().required().max(10), street: yup.string().required().max(255), }); +const getStoreSchema = yup.object() + .shape({ + id: yup.string().length(36).required() +}); let StoreResolver = class StoreResolver { - constructor() { - this.storeCollection = getStores(); - } async stores() { - return await this.storeCollection; + return await getStores(); + } + async store(id /* ,@Arg("withProducts", { nullable: true }) withProducts: boolean*/) { + // check validity + return await getStoreSchema + .validate({ id: id }) + .then(validData => { + return getStore(validData.id); + }) + .catch(err => { + return new UserInputError('Invalid input', { validationErrors: err.errors }); + }); + } + //Extend the Store type with a list of its products. + async products(store) { + return await getStoreProducts(store.id); } async createStore(input) { // check validity @@ -46,11 +62,25 @@ let StoreResolver = class StoreResolver { } }; __decorate([ - Query(returns => [Store], { description: "Get all the stores" }), + Query(() => [Store], { description: "Get all the stores" }), __metadata("design:type", Function), __metadata("design:paramtypes", []), __metadata("design:returntype", Promise) ], StoreResolver.prototype, "stores", null); +__decorate([ + Query(() => Store, { description: "Get a specific store" }), + __param(0, Arg("id")), + __metadata("design:type", Function), + __metadata("design:paramtypes", [String /* ,@Arg("withProducts", { nullable: true }) withProducts: boolean*/]), + __metadata("design:returntype", Promise) +], StoreResolver.prototype, "store", null); +__decorate([ + FieldResolver(() => [Product]), + __param(0, Root()), + __metadata("design:type", Function), + __metadata("design:paramtypes", [Store]), + __metadata("design:returntype", Promise) +], StoreResolver.prototype, "products", null); __decorate([ Mutation(() => Store, { description: "Create a new store" }), __param(0, Arg("input")), @@ -59,6 +89,6 @@ __decorate([ __metadata("design:returntype", Promise) ], StoreResolver.prototype, "createStore", null); StoreResolver = __decorate([ - Resolver() + Resolver(() => Store) ], StoreResolver); export { StoreResolver }; diff --git a/src/resolvers.ts b/src/resolvers.ts index f37789c..2a52c89 100644 --- a/src/resolvers.ts +++ b/src/resolvers.ts @@ -1,7 +1,7 @@ import "reflect-metadata"; -import { Resolver, Query, Mutation, Arg } from "type-graphql"; -import { Store, StoreInput } from "./typeDefs.js"; -import { createStore, getStores } from "./data.js"; +import { Resolver, Query, Mutation, Arg, FieldResolver, Root } from "type-graphql"; +import { Store, StoreInput, Product } from "./typeDefs.js"; +import { createStore, getStores, getStore, getStoreProducts } from "./data.js"; import * as yup from 'yup'; import { UserInputError } from "apollo-server"; @@ -15,18 +15,41 @@ const createStoreSchema = yup.object() street: yup.string().required().max(255), }); +const getStoreSchema = yup.object() + .shape({ + id: yup.string().length(36).required() + }) -@Resolver() + +@Resolver(() => Store) export class StoreResolver { - private storeCollection: Store[] = getStores(); - @Query(returns => [Store], { description: "Get all the stores" }) + @Query(() => [Store], { description: "Get all the stores" }) async stores(): Promise { - return await this.storeCollection; + return await getStores(); + } + @Query(() => Store, { description: "Get a specific store" }) + async store(@Arg("id") id: String/* ,@Arg("withProducts", { nullable: true }) withProducts: boolean*/): Promise { + // check validity + return await getStoreSchema + .validate({ id: id }) + .then(validData => { + return getStore(validData.id); + }) + .catch(err => { + return new UserInputError('Invalid input', { validationErrors: err.errors }); + }); } + //Extend the Store type with a list of its products. + @FieldResolver(() => [Product]) + async products(@Root() store: Store): Promise<[Product]> { + return await getStoreProducts(store.id); + } + + @Mutation(() => Store, { description: "Create a new store" }) - async createStore(@Arg("input") input: StoreInput) { + async createStore(@Arg("input") input: StoreInput): Promise { // check validity return await createStoreSchema .validate(input) @@ -37,7 +60,6 @@ export class StoreResolver { .catch(err => { return new UserInputError('Invalid input', { validationErrors: err.errors }); }); - } } diff --git a/src/typeDefs.js b/src/typeDefs.js index 11e624a..d56a651 100644 --- a/src/typeDefs.js +++ b/src/typeDefs.js @@ -10,7 +10,7 @@ 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, InputType, Int } from "type-graphql"; +import { ObjectType, Field, InputType, Int, Float } from "type-graphql"; let Store = class Store { }; __decorate([ @@ -37,6 +37,10 @@ __decorate([ Field(), __metadata("design:type", String) ], Store.prototype, "street", void 0); +__decorate([ + Field(type => [Product]), + __metadata("design:type", Array) +], Store.prototype, "products", void 0); Store = __decorate([ ObjectType() ], Store); @@ -67,3 +71,25 @@ StoreInput = __decorate([ InputType() ], StoreInput); export { StoreInput }; +let Product = class Product { +}; +__decorate([ + Field(), + __metadata("design:type", String) +], Product.prototype, "id", void 0); +__decorate([ + Field(), + __metadata("design:type", String) +], Product.prototype, "name", void 0); +__decorate([ + Field(), + __metadata("design:type", String) +], Product.prototype, "description", void 0); +__decorate([ + Field(type => Float), + __metadata("design:type", Number) +], Product.prototype, "price", void 0); +Product = __decorate([ + ObjectType() +], Product); +export { Product }; diff --git a/src/typeDefs.ts b/src/typeDefs.ts index d3ef753..25c32cb 100644 --- a/src/typeDefs.ts +++ b/src/typeDefs.ts @@ -2,8 +2,7 @@ // which ways the data can be fetched from the GraphQL server. import "reflect-metadata"; -import { ObjectType, Field, ID, InputType, Int } from "type-graphql"; -import { number } from "yup/lib/locale"; +import { ObjectType, Field, InputType, Int, Float } from "type-graphql"; @ObjectType() @@ -20,6 +19,8 @@ export class Store { postalCode: string @Field() street: string + @Field(type => [Product]) + products?: [Product] } @InputType() export class StoreInput { @@ -33,4 +34,16 @@ export class StoreInput { postalCode: string @Field() street: string +} + +@ObjectType() +export class Product { + @Field() + id: string; + @Field() + name: string; + @Field() + description: string; + @Field(type => Float) + price: number; } \ No newline at end of file