From e1a90670f6695bdfa0a3fec653392b85657a4c36 Mon Sep 17 00:00:00 2001 From: leonnicolas Date: Thu, 24 Sep 2020 17:29:23 +0200 Subject: [PATCH] use transaktions for some updates --- src/datasources/db/cargobikeAPI.ts | 39 +++++++++++++++++++----- src/datasources/db/lendingstationAPI.ts | 2 +- src/datasources/db/providerAPI.ts | 40 +++++++++++++++++++++++++ src/model/ContactPerson.ts | 2 +- src/model/Provider.ts | 4 +++ src/resolvers/providerResolvers.ts | 25 +++++++++++++++- src/schema/type-defs.ts | 27 ++++++++++++----- 7 files changed, 121 insertions(+), 18 deletions(-) diff --git a/src/datasources/db/cargobikeAPI.ts b/src/datasources/db/cargobikeAPI.ts index 29a025f..27c3d24 100644 --- a/src/datasources/db/cargobikeAPI.ts +++ b/src/datasources/db/cargobikeAPI.ts @@ -5,6 +5,7 @@ import { GraphQLError } from 'graphql'; import { BikeEvent } from '../../model/BikeEvent'; import { Equipment } from '../../model/Equipment'; import { Engagement } from '../../model/Engagement'; +import { Provider } from '../../model/Provider'; /** * extended datasource to feed resolvers with data about cargoBikes @@ -47,6 +48,14 @@ export class CargoBikeAPI extends DataSource { .getOne())?.cargoBike; } + async cargoBikesByProviderId (id: number) { + return await this.connection + .createQueryBuilder() + .relation(Provider, 'cargoBikes') + .of(id) + .loadMany(); + } + async lockCargoBike (id: number, req: any, dataSources: any) { if (await this.lockEntity(CargoBike, 'cargobike', id, req, dataSources)) { return this.findCargoBikeById(id); @@ -206,13 +215,29 @@ export class CargoBikeAPI extends DataSource { * @param param0 cargoBike to be created */ async createCargoBike ({ cargoBike }: { cargoBike: any }) { - const inserts = await this.connection.manager - .createQueryBuilder() - .insert() - .into(CargoBike) - .values([cargoBike]) - .returning('*') - .execute(); + let inserts: any; + try { + await this.connection.transaction(async (entityManager:any) => { + inserts = await entityManager.getRepository(CargoBike) + .createQueryBuilder('cargobike') + .insert() + .values([cargoBike]) + .returning('*') + .execute(); + await entityManager.getRepository(CargoBike) + .createQueryBuilder('cargobike') + .relation(CargoBike, 'lendingStation') + .of(inserts.identifiers[0].id) + .set(cargoBike?.lendingStationId); + await entityManager.getRepository(CargoBike) + .createQueryBuilder('cargobike') + .relation(CargoBike, 'provider') + .of(inserts.identifiers[0].id) + .set(cargoBike?.providerId); + }); + } catch (e: any) { + return new GraphQLError('Transaction could not be completed'); + } const newbike = inserts.generatedMaps[0]; newbike.id = inserts.identifiers[0].id; return newbike; diff --git a/src/datasources/db/lendingstationAPI.ts b/src/datasources/db/lendingstationAPI.ts index b2ee2be..ed5fc44 100644 --- a/src/datasources/db/lendingstationAPI.ts +++ b/src/datasources/db/lendingstationAPI.ts @@ -38,7 +38,7 @@ export class LendingStationAPI extends DataSource { return await this.connection.getRepository(LendingStation) .createQueryBuilder('lendingStation') .leftJoinAndSelect('lendingStation.cargoBikes', 'cargoBikes') - .where('"cargoBikes"."lendingStationId" = :id', { id: id }) + .where('"cargoBikes".id = :id', { id: id }) .getOne().catch(() => { return null; }); } diff --git a/src/datasources/db/providerAPI.ts b/src/datasources/db/providerAPI.ts index 8bbfd4a..e273f05 100644 --- a/src/datasources/db/providerAPI.ts +++ b/src/datasources/db/providerAPI.ts @@ -1,4 +1,5 @@ import { DataSource } from 'apollo-datasource'; +import { GraphQLError } from 'graphql'; import { Connection, getConnection } from 'typeorm'; import { Provider } from '../../model/Provider'; @@ -16,4 +17,43 @@ export class ProviderAPI extends DataSource { .where('provider.id = :id', { id: id }) .getOne().catch(() => { return null; }); } + + async provider (offset: number, limit: number) { + return await this.connection.getRepository(Provider) + .createQueryBuilder('provider') + .select() + .offset(offset) + .limit(limit) + .getMany(); + } + + async createProvider (provider: any) { + let inserts: any; + try { + await this.connection.transaction(async (entityManager: any) => { + inserts = await entityManager.getRepository(Provider) + .createQueryBuilder('provider') + .insert() + .values([provider]) + .returning('*') + .execute(); + await entityManager.getRepository(Provider) + .createQueryBuilder('provider') + .relation(Provider, 'cargoBikes') + .of(inserts.identifiers[0].id) + .add(provider.cargoBikeIds); + await entityManager.getRepository(Provider) + .createQueryBuilder('provider') + .relation(Provider, 'contactPersons') + .of(inserts.identifiers[0].id) + .add(provider.contactPersonIds); + }); + } catch (e: any) { + console.log(e); + return new GraphQLError('Transaction could not be completed'); + } + const ret = inserts.generatedMaps[0]; + ret.id = inserts.identifiers[0].id; + return ret; + } } diff --git a/src/model/ContactPerson.ts b/src/model/ContactPerson.ts index cb3e0b6..34476b0 100644 --- a/src/model/ContactPerson.ts +++ b/src/model/ContactPerson.ts @@ -16,7 +16,7 @@ export class ContactPerson { }) lendingStations: LendingStation[]; - @ManyToMany(type => Provider, provider => provider.contactPersons, { + @ManyToOne(type => Provider, provider => provider.contactPersons, { nullable: true }) provider: Provider[]; diff --git a/src/model/Provider.ts b/src/model/Provider.ts index 61053a8..4c9d652 100644 --- a/src/model/Provider.ts +++ b/src/model/Provider.ts @@ -1,6 +1,7 @@ /* eslint no-unused-vars: "off" */ import { PrimaryGeneratedColumn, Column, OneToMany, Entity, OneToOne, ChildEntity } from 'typeorm'; +import { CargoBike } from './CargoBike'; import { ContactInformation } from './ContactInformation'; import { ContactPerson } from './ContactPerson'; import { LendingStation } from './LendingStation'; @@ -37,6 +38,9 @@ export class Provider { }) contactPersons: ContactPerson[]; + @OneToMany(type => CargoBike, cargoBike => cargoBike.provider) + cargoBikes: CargoBike[]; + @Column() isPrivatePerson: boolean; diff --git a/src/resolvers/providerResolvers.ts b/src/resolvers/providerResolvers.ts index 1bcc659..9177790 100644 --- a/src/resolvers/providerResolvers.ts +++ b/src/resolvers/providerResolvers.ts @@ -3,7 +3,14 @@ import { Permission } from '../datasources/userserver/permission'; export default { Query: { - providerById: (_: any, { id }: { id: number, limit: number }, { dataSources, req }: { dataSources: any, req: any }) => { + providers: (_: any, { offset, limit }: { offset: number, limit: number }, { dataSources, req }: { dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.ReadBike)) { + return dataSources.providerAPI.provider(offset, limit); + } else { + return new GraphQLError('Insufficient Permissions'); + } + }, + providerById: (_: any, { id }: { id: number }, { dataSources, req }: { dataSources: any, req: any }) => { if (req.permissions.includes(Permission.ReadBike)) { return dataSources.providerAPI.providerById(id); } else { @@ -11,6 +18,22 @@ export default { } } }, + Provider: { + cargoBikes: (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.ReadBike)) { + return dataSources.cargoBikeAPI.cargoBikesByProviderId(parent.id); + } else { + return new GraphQLError('Insufficient Permissions'); + } + } + }, Mutation: { + createProvider: (_: any, { provider }: { provider: number }, { dataSources, req }: { dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.WriteBike)) { + return dataSources.providerAPI.createProvider(provider); + } else { + return new GraphQLError('Insufficient Permissions'); + } + } } }; diff --git a/src/schema/type-defs.ts b/src/schema/type-defs.ts index 37128f5..6a1fc29 100644 --- a/src/schema/type-defs.ts +++ b/src/schema/type-defs.ts @@ -78,8 +78,9 @@ input CargoBikeCreateInput { "Sticker State" stickerBikeNameState: StickerBikeNameState note: String - provider: String + providerId: ID insuranceData: InsuranceDataCreateInput! + lendingStationId: ID taxes: TaxesCreateInput! } @@ -108,12 +109,12 @@ input CargoBikeUpdateInput { dimensionsAndLoad: DimensionsAndLoadUpdateInput "Refers to equipment that is not unique. See kommentierte info tabelle -> Fragen -> Frage 2" miscellaneousEquipment: [String] - lendingStationId: ID "Sticker State" stickerBikeNameState: StickerBikeNameState note: String provider: String insuranceData: InsuranceDataUpdateInput + lendingStationId: ID taxes: TaxesUpdateInput "will keep Bike locked if set to true, default = false" keepLock: Boolean @@ -504,19 +505,26 @@ enum StickerBikeNameState { UNKNOWN } -"(dt. Anbieter)" +"(dt. Anbieter) bezieht sich auf die Benziehung einer Person oder Organisation zum Lastenrad" type Provider { id: ID! - name: String! formularName: String - - - providerContactPerson: [ContactInformation] + contactPersons: [ContactInformation]! isPrivatePerson: Boolean! organisation: Organisation cargoBikes: [CargoBike]! } +"(dt. Anbieter)" +input ProviderCreateInput { + formularName: String! + "i think it makes more sense to create Provider and then add new ContactPersons" + contactPersonIds: [ID]! + isPrivatePerson: Boolean! + organisationId: ID + cargoBikeIds: [ID]! +} + type ContactInformation { id: ID! name: String! @@ -558,6 +566,7 @@ input ContactInformationUpdateInput { note: String } +"describes Relation of Contact to Provider" type ContactPerson { id: ID! intern: Boolean! @@ -703,7 +712,7 @@ type Query { equipment(offset: Int!, limit: Int!): [Equipment]! "equipment by id, will return null if id not found" equipmentById(id: ID!): Equipment - providers: [Provider]! + providers(offset: Int!, limit: Int!): [Provider]! "particcipant by id" participantById(id:ID!): Participant "p" @@ -747,6 +756,8 @@ type Mutation { "createContacPerson ,return null if contactInformationId does not exist" createContactPerson(contactPerson: ContactPersonCreateInput): ContactPerson updateContactPerson(contactPerson: ContactPersonUpdateInput): ContactPerson + "create Provider, if cargoBikeIds or contactPersonIds are not valid, provider will still be created" + createProvider(provider: ProviderCreateInput!): Provider! }