diff --git a/src/datasources/db/cargobikeAPI.ts b/src/datasources/db/cargobikeAPI.ts index 4575c40..ee94e41 100644 --- a/src/datasources/db/cargobikeAPI.ts +++ b/src/datasources/db/cargobikeAPI.ts @@ -3,6 +3,8 @@ import { getConnection, Connection } from 'typeorm'; import { CargoBike } from '../../model/CargoBike'; import { GraphQLError } from 'graphql'; import { BikeEvent } from '../../model/BikeEvent'; +import { Equipment } from '../../model/Equipment'; + /** * extended datasource to feed resolvers with data about cargoBikes */ @@ -15,8 +17,8 @@ export class CargoBikeAPI extends DataSource { async getCargoBikes (offset: number, limit: number) { return await this.connection.createQueryBuilder() - .select('cargoBikes') - .from(CargoBike, 'cargoBikes') + .select('cargoBike') + .from(CargoBike, 'cargoBike') .orderBy('name', 'ASC') .offset(offset) .limit(limit) @@ -24,16 +26,16 @@ export class CargoBikeAPI extends DataSource { } /** - * Finds cargo bike by id, retuns error if id not found + * Finds cargo bike by id, retuns null if id was not found * @param param0 id of bike */ async findCargoBikeById ({ id }:{id: any}) { - return await this.connection.manager - .createQueryBuilder() + return await this.connection.manager.getRepository(CargoBike).findOne({ id: id }); + /* .createQueryBuilder() .select('cargoBike') .from(CargoBike, 'cargoBike') .where('cargoBike.id = :id', { id }) - .getOne() || new GraphQLError('ID not found'); + .getOne() || new GraphQLError('ID not found'); */ } /** @@ -98,4 +100,78 @@ export class CargoBikeAPI extends DataSource { .where('bikeEvent.id = :id', { id: id }) .getOne(); } + + async findEquipmentById (id: number) { + return await this.connection.getRepository(Equipment) + .createQueryBuilder('equipment') + .select() + .where('equipment.id = :id', { id: id }) + .getOne(); + } + + async findEquipmentJoinBikeById (id: number) { + return await this.connection.getRepository(Equipment) + .createQueryBuilder('equipment') + .leftJoinAndSelect('equipment.cargoBike', 'cargoBike') + .where('equipment.id = :id', { id: id }) + .getOne(); + } + + async createEquipment ({ equipment }: { equipment: any }) { + const inserts = await this.connection.getRepository(Equipment) + .createQueryBuilder('equipment') + .insert() + .into(Equipment) + .values([equipment]) + .returning('*') + .execute(); + if (equipment.cargoBikeId) { + await this.connection + .createQueryBuilder() + .relation(Equipment, 'cargoBike') + .of(equipment.id) + .set(equipment.cargoBikeId); + return this.findEquipmentJoinBikeById(inserts.identifiers[0].id); + } + return this.findEquipmentById(inserts.identifiers[0].id); + } + + /** + * Will update Equipment, crashes when id not in db or cargoBikeId not db. + * Will return updated Equipment joined with CargoBike only if cargoBike is was set in param0 + * @param param0 struct with equipment properites + */ + async updateEquipment ({ equipment }: { equipment: any }) { + console.log(equipment); + const cargoBikeId = equipment.cargoBikeId; + delete equipment.cargoBikeId; + console.log(equipment); + const inserts = await this.connection.getRepository(Equipment) + .createQueryBuilder('equipment') + .update() + .set({ ...equipment }) + .where('id = :id', { id: equipment.id }) + .returning('*') + .execute(); + console.log(inserts.raw[0]); + if (cargoBikeId || cargoBikeId === null) { + await this.connection.getRepository(Equipment) + .createQueryBuilder() + .relation(Equipment, 'cargoBike') + .of(equipment.id) + .set(cargoBikeId); + return this.findEquipmentJoinBikeById(equipment.id); + } + return this.findEquipmentById(equipment.id); + } + + async getEquipment (offset: number, limit: number) { + return await this.connection.getRepository(Equipment) + .createQueryBuilder('equipment') + .leftJoinAndSelect('equipment.cargoBike', 'cargoBike') + .orderBy('title', 'ASC') + .offset(offset) + .limit(limit) + .getMany(); + } } diff --git a/src/model/CargoBike.ts b/src/model/CargoBike.ts index 41fa497..8472442 100644 --- a/src/model/CargoBike.ts +++ b/src/model/CargoBike.ts @@ -72,7 +72,8 @@ export class CargoBike extends Bike { name: string; @OneToMany(type => Equipment, equipment => equipment.cargoBike, { - nullable: true + nullable: true, + eager: true }) equipment: Equipment[]; diff --git a/src/model/Equipment.ts b/src/model/Equipment.ts index 4dfd195..ccc3197 100644 --- a/src/model/Equipment.ts +++ b/src/model/Equipment.ts @@ -1,8 +1,22 @@ -import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm'; +import { Entity, PrimaryGeneratedColumn, Column, JoinColumn, ManyToOne } from 'typeorm'; import { CargoBike } from './CargoBike'; @Entity() export class Equipment { + setValues ({ id, serialNo, title, description, cargoBike }: { + id: number, + serialNo: string, + title: string, + description: string, + cargoBike: CargoBike + }) { + this.id = id; + this.serialNo = serialNo; + this.title = title; + this.description = description; + this.cargoBike = cargoBike; + } + @PrimaryGeneratedColumn() id: number; @@ -17,8 +31,13 @@ export class Equipment { }) description: string; - @OneToMany(type => CargoBike, cargoBike => cargoBike.equipment, { + @ManyToOne(type => CargoBike, cargoBike => cargoBike.equipment, { nullable: true }) + @JoinColumn({ + name: 'cargoBikeId', referencedColumnName: 'id' + }) cargoBike: CargoBike; + + cargoBikeId: number; } diff --git a/src/resolvers/cargobikeResolver.ts b/src/resolvers/cargobikeResolver.ts index f7232d6..4ece04a 100644 --- a/src/resolvers/cargobikeResolver.ts +++ b/src/resolvers/cargobikeResolver.ts @@ -23,6 +23,20 @@ export default { } else { return new GraphQLError('Insufficiant Permissions'); } + }, + equipment: (_:any, { offset, limit }: { offset: number, limit: number }, { dataSources, req }: { dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.ReadBike)) { + return dataSources.cargoBikeAPI.getEquipment(offset, limit); + } else { + return new GraphQLError('Insufficiant Permissions'); + } + }, + equipmentById: (_:any, { id }: { id: number }, { dataSources, req }: { dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.ReadBike)) { + return dataSources.cargoBikeAPI.findEquipmentJoinBikeById(id); + } else { + return new GraphQLError('Insufficiant Permissions'); + } } }, Mutation: { @@ -46,6 +60,20 @@ export default { } else { return new GraphQLError('Insufficient Permissions'); } + }, + createEquipment: (_: any, { equipment }: { equipment: any }, { dataSources, req }: { dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.WriteBike)) { + return dataSources.cargoBikeAPI.createEquipment({ equipment }); + } else { + return new GraphQLError('Insufficient Permissions'); + } + }, + updateEquipment: (_: any, { equipment }: { equipment: any }, { dataSources, req }: { dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.WriteBike)) { + return dataSources.cargoBikeAPI.updateEquipment({ equipment }); + } else { + return new GraphQLError('Insufficient Permissions'); + } } } }; diff --git a/src/schema/type-defs.ts b/src/schema/type-defs.ts index 3217016..19f9469 100644 --- a/src/schema/type-defs.ts +++ b/src/schema/type-defs.ts @@ -266,7 +266,32 @@ type Equipment { TODO unclear what this means. tomy fragen """ investable: Boolean - name: String + title: String! + description: String + cargoBike: CargoBike +} + +input EquipmentCreateInput { + serialNo: String! + """ + TODO unclear what this means. tomy fragen + """ + title: String! + description: String + investable: Boolean + cargoBikeId: ID +} + +input EquipmentUpdateInput { + id: ID! + serialNo: String + """ + TODO unclear what this means. tomy fragen + """ + title: String + description: String + investable: Boolean + cargoBikeId: ID } "An Event is a point in time, when the state of the bike somehow changed." @@ -294,7 +319,7 @@ input BikeEventCreateInput { documents: [String]! } -"TODO: Some eventTypes are missing (und auf deutsch)" +"TODO: Some eventTypes are missing" enum BikeEventType { """ The enum EventType can also be represented as an enum in postgresQL. @@ -587,12 +612,16 @@ input AddressUpdateInput { } type Query { + "Will (evetually) return all properties of cargo bike" cargoBikeById(id:ID!): CargoBike - "returns cargoBikes ordered by name ascending" + "returns cargoBikes ordered by name ascending, relations are not loaded, use cargoBikeById instead" cargoBikes(offset: Int!, limit: Int!): [CargoBike]! "not important, you can just use providerById {cargoBikes}" - cargoBikesByProvider(providerId:ID!): [CargoBike]! providerById(id:ID!): Provider + "unique equipment with pagination, contains relation to bike (with no further joins), so if you wanna know more about the bike, use cargoBikeById" + equipment(offset: Int!, limit: Int!): [Equipment]! + "equipment by id, will return null if id not found" + equipmentById(id: ID!): Equipment providers: [Provider]! participantById(id:ID!): Participant participants: [ Participant]! @@ -608,6 +637,10 @@ type Mutation { createCargoBike(cargoBike: CargoBikeCreateInput!): CargoBike! "updates cargoBike of given ID with supplied fields and returns updated cargoBike" updateCargoBike(cargoBike: CargoBikeUpdateInput!): CargoBike! + "creates new peace of unique Equipment, the returned Equipment will contain a cargoBike, but that cargoBike will not contain equipment" + createEquipment(equipment: EquipmentCreateInput!): Equipment! + "update Equipment, returns updated equipment. CargoBike will be null, if cargoBikeId is not set. Pass null for cargoBikeIs to delete the relation" + updateEquipment(equipment: EquipmentUpdateInput!): Equipment! "creates new lendingStation and returns lendingStation with new ID" createLendingStation(lendingStation: LendingStationCreateInput): LendingStation! "updates lendingStation of given ID with supplied fields and returns updated lendingStation"