diff --git a/Server/prisma/schema.prisma b/Server/prisma/schema.prisma index 1a13e28b..78961db4 100644 --- a/Server/prisma/schema.prisma +++ b/Server/prisma/schema.prisma @@ -37,7 +37,7 @@ model POI { typeId Int type POIType @relation(fields: [typeId], references: [uid]) trackId Int - track Track @relation(fields: [trackId], references: [uid]) + track Track @relation(fields: [trackId], references: [uid], onDelete: Cascade) } model Track { @@ -62,12 +62,12 @@ model VehicleType { model Vehicle { uid Int @id @default(autoincrement()) name String - + typeId Int type VehicleType @relation(fields: [typeId], references: [uid]) trackId Int track Track @relation(fields: [trackId], references: [uid]) - + tracker Tracker[] logs Log[] diff --git a/Server/src/routes/poi.route.ts b/Server/src/routes/poi.route.ts index a58198a0..73b8cff8 100644 --- a/Server/src/routes/poi.route.ts +++ b/Server/src/routes/poi.route.ts @@ -4,7 +4,7 @@ import { Position, UpdatePointOfInterest } from "../models/api" import { logger } from "../utils/logger" import POIService from "../services/poi.service" import { Feature, GeoJsonProperties, Point } from "geojson" -import { POI, POIType, Track } from "@prisma/client" +import { POI, POIType, Track, Prisma } from "@prisma/client" import database from "../services/database.service" import GeoJSONUtils from "../utils/geojsonUtils" import please_dont_crash from "../utils/please_dont_crash" @@ -199,15 +199,16 @@ export class PoiRoute { const enrichedPoint = (await POIService.enrichPOIPosition(geopos, track)) ?? undefined - const updatedPOI: POI | null = await database.pois.update( - poiId, - userData.name, - userData.description, - userData.typeId, - userData.trackId, - enrichedPoint, - userData.isTurningPoint - ) + // Note: geopos is from type GeoJSON.Feature and can't be parsed directly into Prisma.InputJsonValue + // Therefore we cast it into unknown first. + const updatedPOI: POI | null = await database.pois.update(userData.id!, { + name: userData.name, + description: userData.description, + position: enrichedPoint as unknown as Prisma.InputJsonValue, + isTurningPoint: userData.isTurningPoint, + typeId: userData.typeId, + trackId: track!.uid + }) if (!updatedPOI) { logger.error(`Could not update poi with id ${userData.id}`) diff --git a/Server/src/routes/poitype.route.ts b/Server/src/routes/poitype.route.ts index 5321c4cd..d3e015aa 100644 --- a/Server/src/routes/poitype.route.ts +++ b/Server/src/routes/poitype.route.ts @@ -85,7 +85,7 @@ export class PoiTypeRoute { // TODO: ensure that the icon is a member of the enum (or check if the type guard checks that) const { name, icon, description }: CreatePOIType = req.body - const poiType: POIType | null = await database.pois.saveType(name, icon.toString(), description) + const poiType: POIType | null = await database.pois.saveType({ name, icon: icon.toString(), description }) if (!poiType) { logger.error("Could not create poi type") res.sendStatus(500) @@ -118,7 +118,11 @@ export class PoiTypeRoute { return } - type = await database.pois.updateType(typeId, userData.name, userData.icon.toString(), userData.description) + type = await database.pois.updateType(typeId, { + name: userData.name, + icon: userData.icon.toString(), + description: userData.description + }) if (!type) { logger.error(`Could not update poi type with id ${userData.id}`) res.sendStatus(500) diff --git a/Server/src/routes/tracker.route.ts b/Server/src/routes/tracker.route.ts index 544ab54a..cd3225cc 100644 --- a/Server/src/routes/tracker.route.ts +++ b/Server/src/routes/tracker.route.ts @@ -4,7 +4,8 @@ import { authenticateJWT, jsonParser } from "." import TrackerService from "../services/tracker.service" import { UplinkTracker } from "../models/api.tracker" import please_dont_crash from "../utils/please_dont_crash" -import { Tracker, Vehicle } from "@prisma/client" +import { Prisma, Tracker, Vehicle } from "@prisma/client" +import VehicleService from "../services/vehicle.service" import database from "../services/database.service" import { Tracker as APITracker } from "../models/api" @@ -82,7 +83,11 @@ export class TrackerRoute { private async createTracker(req: Request, res: Response): Promise { const apiTracker: APITracker = req.body - const tracker: Tracker | null = await database.trackers.save(apiTracker.id, apiTracker.vehicleId, apiTracker.data) + const tracker: Tracker | null = await database.trackers.save({ + uid: apiTracker.id, + vehicleId: apiTracker.vehicleId, + data: apiTracker.data as Prisma.InputJsonValue + }) if (!tracker) { logger.error("Could not create tracker") res.sendStatus(500) @@ -114,7 +119,10 @@ export class TrackerRoute { return } - tracker = await database.trackers.update(trackerId, userData.vehicleId, userData.data) + tracker = await database.trackers.update(trackerId, { + vehicleId: userData.vehicleId, + data: userData.data as Prisma.InputJsonValue + }) if (!tracker) { logger.error(`Could not update tracker with id ${userData.id}`) res.sendStatus(500) diff --git a/Server/src/routes/vehicle.route.ts b/Server/src/routes/vehicle.route.ts index 7c6e7592..c0fdfcd4 100644 --- a/Server/src/routes/vehicle.route.ts +++ b/Server/src/routes/vehicle.route.ts @@ -293,7 +293,11 @@ export class VehicleRoute { trackers.push(maybeTracker) } - const vehicle: Vehicle | null = await database.vehicles.save(type.uid, userData.track, userData.name) + const vehicle: Vehicle | null = await database.vehicles.save({ + name: userData.name, + typeId: type.uid, + trackId: userData.track + }) if (!vehicle) { logger.error(`Could not create vehicle`) res.sendStatus(500) @@ -301,7 +305,7 @@ export class VehicleRoute { } for (const tracker of trackers) { - const updatedTracker = await database.trackers.update(tracker.uid, vehicle.uid) + const updatedTracker = await database.trackers.update(tracker.uid, { vehicleId: vehicle.uid }) if (!updatedTracker) { logger.error(`Could not attach tracker to created vehicle.`) res.sendStatus(500) @@ -376,7 +380,11 @@ export class VehicleRoute { trackers.push(tracker) } - const vehicle = await database.vehicles.update(vehicleId, type.uid, userData.track, userData.name) + const vehicle = await database.vehicles.update(vehicleId, { + typeId: type.uid, + trackId: userData.track, + name: userData.name + }) if (!vehicle) { logger.error(`Could not update vehicle with id ${vehicleId}`) res.sendStatus(500) @@ -384,11 +392,11 @@ export class VehicleRoute { } for (const tracker of prevTrackers) { - database.trackers.update(tracker.uid, null) + database.trackers.update(tracker.uid, { vehicleId: null }) } for (const tracker of trackers) { - const trackerToUpdate: Tracker | null = await database.trackers.update(tracker.uid, vehicleId) + const trackerToUpdate: Tracker | null = await database.trackers.update(tracker.uid, { vehicleId: vehicleId }) if (!trackerToUpdate) { logger.error(`Could not set tracker with tracker-id ${tracker}`) res.sendStatus(500) diff --git a/Server/src/routes/vehicletype.route.ts b/Server/src/routes/vehicletype.route.ts index c7928331..f0c16950 100644 --- a/Server/src/routes/vehicletype.route.ts +++ b/Server/src/routes/vehicletype.route.ts @@ -125,11 +125,11 @@ export class VehicleTypeRoute { // TODO: input validation - const vehicleType: VehicleType | null = await database.vehicles.saveType( - userData.name, - userData.icon, - userData.description - ) + const vehicleType: VehicleType | null = await database.vehicles.saveType({ + name: userData.name, + icon: userData.icon, + description: userData.description + }) if (!vehicleType) { // TODO: differentiate different error causes: // Constraint violation => 409 @@ -195,7 +195,11 @@ export class VehicleTypeRoute { // type = await VehicleService.renameVehicleType(type, userData.name) // TODO: What about the description?! // update all properties atomically, by directly talking to the database controller - type = await database.vehicles.updateType(type.uid, userData.name, userData.icon, userData.description) + type = await database.vehicles.updateType(type.uid, { + name: userData.name, + icon: userData.icon, + description: userData.description + }) if (!type) { // TODO: differentiate different error causes: diff --git a/Server/src/services/db/log.controller.ts b/Server/src/services/db/log.controller.ts index baa897bc..1a0f02d9 100644 --- a/Server/src/services/db/log.controller.ts +++ b/Server/src/services/db/log.controller.ts @@ -70,13 +70,15 @@ export default class LogController { * Removes a log from the database. * * @param uid - Indicator which log should be removed + * @returns True if the removal was successful. Otherwise throws an Error. */ - public async remove(uid: number): Promise { + public async remove(uid: number): Promise { await this.prisma.log.delete({ where: { uid: uid } }) + return true } /** @@ -84,7 +86,7 @@ export default class LogController { * If a trackerId is given the list will be filtered for this specific tracker. * If a vehicleId is given the list will be filtered for this specific vehicle. * - * @param limit - Number of entries this method should deliver. Default is all (undefined) + * @param limit - Number of entries this method should deliver. Default is all (undefined). * @param vehicleId - Vehicle to filter for (Optional) * @param trackerId - Tracker to filter for (Optional) * @returns Log[] - List of all logs @@ -134,7 +136,7 @@ export default class LogController { */ public async getNewestLogs(vehicleId: number, max_sec: number = 300): Promise { // Earliest date which should be considered - let max_date = new Date(Date.now() - max_sec * 1000) + const max_date = new Date(Date.now() - max_sec * 1000) return await this.prisma.log.findMany({ where: { diff --git a/Server/src/services/db/poi.controller.ts b/Server/src/services/db/poi.controller.ts index 98a3632e..b19b080e 100644 --- a/Server/src/services/db/poi.controller.ts +++ b/Server/src/services/db/poi.controller.ts @@ -1,7 +1,4 @@ -import { PrismaClient, Prisma } from ".prisma/client" -import type { POI, POIType } from ".prisma/client" -import { logger } from "../../utils/logger" -import { Feature, Point } from "geojson" +import { POI, POIType, PrismaClient, Prisma } from "@prisma/client" /** * POIController class @@ -34,71 +31,53 @@ export default class POIController { /** * Saves a type for POIs in the database. * + * The parameter are given via object deconstruction from the model `POIType`! + * Currently given parameters are: * @param name - **unique** name of the type of poi. * @param icon - unique icon name for visualization * @param description - an optional description for the type of poi. - * @returns POIType | null if an error occurs. + * @returns POIType */ - public async saveType(name: string, icon: string, description?: string): Promise { - try { - return await this.prisma.pOIType.create({ - data: { - name: name, - icon: icon, - description: description - } - }) - } catch (e) { - logger.debug(e) - return null - } + public async saveType(args: Prisma.POITypeCreateInput): Promise { + return await this.prisma.pOIType.create({ + data: args + }) } /** * Updates a type of poi in the database. * * @param uid - Indicator which type should be updated. + * + * The parameter are given via object deconstruction from the model `POIType`! + * Currently given parameters are: * @param name - New name after change. (Optional) * @param icon - New unique icon name for visualization after change. (Optional) * @param description - New description after change. (Optional) * @returns POIType | null if an error occurs. */ - public async updateType(uid: number, name?: string, icon?: string, description?: string): Promise { - try { - return await this.prisma.pOIType.update({ - where: { - uid: uid - }, - data: { - name: name, - icon: icon, - description: description - } - }) - } catch (e) { - logger.debug(e) - return null - } + public async updateType(uid: number, args: Prisma.POITypeUpdateInput): Promise { + return await this.prisma.pOIType.update({ + where: { + uid: uid + }, + data: args + }) } /** * Removes a poi type from the database. * * @param uid - Indicator which type should be removed. - * @returns True | False depending on if the type was removed or not. + * @returns True if the removal was successful. Otherwise throws an Error. */ public async removeType(uid: number): Promise { - try { - await this.prisma.pOIType.delete({ - where: { - uid: uid - } - }) - return true - } catch (e) { - logger.debug(e) - return false - } + await this.prisma.pOIType.delete({ + where: { + uid: uid + } + }) + return true } /** @@ -107,12 +86,7 @@ export default class POIController { * @returns `POIType[]` - List of all types of poi. */ public async getAllTypes(): Promise { - try { - return await this.prisma.pOIType.findMany({}) - } catch (e) { - logger.debug(e) - return [] - } + return await this.prisma.pOIType.findMany({}) } /** @@ -122,16 +96,11 @@ export default class POIController { * @returns POIType | null depending on if the type could be found. */ public async getTypeById(uid: number): Promise { - try { - return await this.prisma.pOIType.findUnique({ - where: { - uid: uid - } - }) - } catch (e) { - logger.debug(e) - return null - } + return await this.prisma.pOIType.findUnique({ + where: { + uid: uid + } + }) } /** @@ -141,16 +110,11 @@ export default class POIController { * @returns POIType | null depending on if the type could be found. */ public async getTypeByName(name: string): Promise { - try { - return await this.prisma.pOIType.findUnique({ - where: { - name: name - } - }) - } catch (e) { - logger.debug(e) - return null - } + return await this.prisma.pOIType.findUnique({ + where: { + name: name + } + }) } // ========================================================= // @@ -159,98 +123,61 @@ export default class POIController { /** * Saves a point of interest (POI) in the database. * + * The parameter are given via object deconstruction from the model `POI`! + * Currently given parameters are: * @param name - **unique** name of the POI * @param typeId - POIType Identifier: Maps a POIType to said POI in the database * @param trackId - Track Identifier : Maps a Track to said POI in the database * @param position - Coordinates to pinpoint the location of said POI. * @param description - optional description of said POI * @param isTurningPoint - optional indicator whether it is possible to turn a vehicle around at this POI - * @returns POI | null if an error occurs. + * @returns POI */ - public async save( - name: string, - typeId: number, - trackId: number, - position: Feature, - description?: string, - isTurningPoint: boolean = false - ): Promise { - try { - return await this.prisma.pOI.create({ - data: { - name: name, - description: description, - typeId: typeId, - trackId: trackId, - position: position as any, // Required, as typescript will not otherwise know that keys in a Point are strings. - isTurningPoint: isTurningPoint - } - }) - } catch (e) { - logger.debug(e) - return null - } + public async save(args: Prisma.POIUncheckedCreateInput): Promise { + // POIUncheckCreateInput is used because of required relations based on the model! + return await this.prisma.pOI.create({ + data: args + }) } /** * Updates a POI in the database. * * @param uid - Indicator which poi should be updated. + * + * The parameter are given via object deconstruction from the model `POI`! + * Currently given parameters are: * @param name - New name after change. (Optional) * @param description - New description after change. (Optional) * @param typeId - New typeId after change. (Optional) * @param trackId - New trackId after change. (Optional) * @param position - New position after change. (Optional) * @param isTurningPoint - indicator whether it is possible to turn a vehicle around at this POI (Optional) - * @returns POI | null if an error occurs. + * @returns POI */ - public async update( - uid: number, - name?: string, - description?: string, - typeId?: number, - trackId?: number, - position?: Feature, - isTurningPoint?: boolean - ): Promise { - try { - return await this.prisma.pOI.update({ - where: { - uid: uid - }, - data: { - name: name, - description: description, - typeId: typeId, - trackId: trackId, - position: position as any, // Required, as typescript will not otherwise know that keys in a Point are strings. - isTurningPoint: isTurningPoint - } - }) - } catch (e) { - logger.debug(e) - return null - } + public async update(uid: number, args: Prisma.POIUncheckedUpdateInput): Promise { + // POIUncheckUpdateInput is used because of required relations based on the model + return await this.prisma.pOI.update({ + where: { + uid: uid + }, + data: args + }) } /** * Removes an poi from the database. * * @param uid - Indicator which poi should be removed. - * @returns True | False depending on if the user was removed or not. + * @returns True if the removal was successful. Otherwise throws an Error. */ public async remove(uid: number): Promise { - try { - await this.prisma.pOI.delete({ - where: { - uid: uid - } - }) - return true - } catch (e) { - logger.debug(e) - return false - } + await this.prisma.pOI.delete({ + where: { + uid: uid + } + }) + return true } /** @@ -260,16 +187,11 @@ export default class POIController { * @returns POI[] - List of all pois. If an trackId was given: List of all pois on this specific track. */ public async getAll(trackId?: number): Promise { - try { - return await this.prisma.pOI.findMany({ - where: { - trackId: trackId - } - }) - } catch (e) { - logger.debug(e) - return [] - } + return await this.prisma.pOI.findMany({ + where: { + trackId: trackId + } + }) } /** @@ -279,20 +201,15 @@ export default class POIController { * @returns POI | null depending on if the poi could be found. */ public async getById(uid: number): Promise { - try { - return await this.prisma.pOI.findUnique({ - where: { - uid: uid - }, - include: { - type: true, - track: true - } - }) - } catch (e) { - logger.debug(e) - return null - } + return await this.prisma.pOI.findUnique({ + where: { + uid: uid + }, + include: { + type: true, + track: true + } + }) } /** @@ -303,16 +220,11 @@ export default class POIController { * @returns POI[] - List of all pois with the given name. If an trackId was given: List of all pois on this specific track with the given name. */ public async getByName(name: string, trackId?: number): Promise { - try { - return await this.prisma.pOI.findMany({ - where: { - name: name, - trackId: trackId - } - }) - } catch (e) { - logger.debug(e) - return [] - } + return await this.prisma.pOI.findMany({ + where: { + name: name, + trackId: trackId + } + }) } } diff --git a/Server/src/services/db/track.controller.ts b/Server/src/services/db/track.controller.ts index b3bbd182..15c1497b 100644 --- a/Server/src/services/db/track.controller.ts +++ b/Server/src/services/db/track.controller.ts @@ -1,156 +1,121 @@ -import { PrismaClient, Prisma } from "@prisma/client" -import type { Track } from "@prisma/client" -import { logger } from "../../utils/logger" - -/** - * TrackController class - * - * Handles track specific access to the database. - * @function - save() - * - update() - * - remove() - * - getAll() - * - getById() - * - getByStop() - * - */ -export default class TrackController { - constructor(private prisma: PrismaClient) {} - - /** - * Saves a tracker in the database. - * - * @param start - Name of the start location. - * @param stop - Name of the end location. - * @param data - JSON Data of the track - * @returns Track | null if an error occurs - */ - public async save(start: string, stop: string, data: any): Promise { - try { - return await this.prisma.track.create({ - data: { - start: start, - stop: stop, - data: data - } - }) - } catch (e) { - logger.debug(e) - return null - } - } - - /** - * Updates a track in the database. - * - * @param uid - Indicator which track should be updated - * @param start - New name of the start location after change (Optional) - * @param stop - New name of the end location after change (Optional) - * @param data - New JSON Data of the track after change (Optional) - * @returns Track | null if an error occurs - */ - public async update(uid: number, start?: string, stop?: string, data?: any): Promise { - try { - return await this.prisma.track.update({ - where: { - uid: uid - }, - data: { - start: start, - stop: stop, - data: data - } - }) - } catch (e) { - logger.debug(e) - return null - } - } - - /** - * Removes a track in the database. - * - * @param uid - Indicator which track should be removed. - * @returns True | False depending on if the track was removed or not. - */ - public async remove(uid: number): Promise { - try { - await this.prisma.track.delete({ - where: { - uid: uid - } - }) - return true - } catch (e) { - logger.debug(e) - return false - } - } - - /** - * Returns a list of all tracks. - * - * @returns Track[] - List of all tracks. - */ - public async getAll(): Promise { - try { - return await this.prisma.track.findMany({}) - } catch (e) { - logger.debug(e) - return [] - } - } - - /** - * Looks up a track given by its uid. - * - * @param uid - Indicator which track should be searched for. - * @returns Track | null depending on if the track could be found. - */ - public async getById(uid: number): Promise { - try { - return await this.prisma.track.findUnique({ - where: { - uid: uid - }, - include: { - poi: true, - vehicle: true - } - }) - } catch (e) { - logger.debug(e) - return null - } - } - - /** - * Looks up any track that has a start or stop at the given location. - * - * @param location - Name of the location to check. - * @returns Track[] - List of tracks that have either start and/or stop at the given location. - */ - public async getByLocation(location: string): Promise { - try { - return await this.prisma.track.findMany({ - where: { - OR: [ - { - start: location - }, - { - stop: location - } - ] - }, - include: { - poi: true, - vehicle: true - } - }) - } catch (e) { - logger.debug(e) - return [] - } - } -} +import { PrismaClient, Prisma, Track } from "@prisma/client" + +/** + * TrackController class + * + * Handles track specific access to the database. + * @function - save() + * - update() + * - remove() + * - getAll() + * - getById() + * - getByStop() + * + */ +export default class TrackController { + constructor(private prisma: PrismaClient) {} + + /** + * Saves a tracker in the database. + * + * The parameter are given via object deconstruction from the model `Track`! + * Currently given parameters are: + * @param start - Name of the start location. + * @param stop - Name of the end location. + * @param data - JSON Data of the track + * @returns Track + */ + public async save(args: Prisma.TrackCreateInput): Promise { + return await this.prisma.track.create({ + data: args + }) + } + + /** + * Updates a track in the database. + * + * @param uid - Indicator which track should be updated + * + * The parameter are given via object deconstruction from the model `Track`! + * Currently given parameters are: + * @param start - New name of the start location after change (Optional) + * @param stop - New name of the end location after change (Optional) + * @param data - New JSON Data of the track after change (Optional) + * @returns Track + */ + public async update(uid: number, args: Prisma.TrackUpdateInput): Promise { + return await this.prisma.track.update({ + where: { + uid: uid + }, + data: args + }) + } + + /** + * Removes a track in the database. + * + * @param uid - Indicator which track should be removed. + * @returns True if the removal was successful. Otherwise throws an Error. + */ + public async remove(uid: number): Promise { + await this.prisma.track.delete({ + where: { + uid: uid + } + }) + return true + } + + /** + * Returns a list of all tracks. + * + * @returns Track[] - List of all tracks. + */ + public async getAll(): Promise { + return await this.prisma.track.findMany({}) + } + + /** + * Looks up a track given by its uid. + * + * @param uid - Indicator which track should be searched for. + * @returns Track | null depending on if the track could be found. + */ + public async getById(uid: number): Promise { + return await this.prisma.track.findUnique({ + where: { + uid: uid + }, + include: { + poi: true, + vehicle: true + } + }) + } + + /** + * Looks up any track that has a start or stop at the given location. + * + * @param location - Name of the location to check. + * @returns Track[] - List of tracks that have either start and/or stop at the given location. + */ + public async getByLocation(location: string): Promise { + return await this.prisma.track.findMany({ + where: { + OR: [ + { + start: location + }, + { + stop: location + } + ] + }, + include: { + poi: true, + vehicle: true + } + }) + } +} diff --git a/Server/src/services/db/tracker.controller.ts b/Server/src/services/db/tracker.controller.ts index 8dfa6adc..968d0399 100644 --- a/Server/src/services/db/tracker.controller.ts +++ b/Server/src/services/db/tracker.controller.ts @@ -1,5 +1,4 @@ -import { PrismaClient, Tracker } from "@prisma/client" -import { logger } from "../../utils/logger" +import { Prisma, PrismaClient, Tracker } from "@prisma/client" /** * TrackerController class @@ -19,69 +18,54 @@ export default class TrackerController { /** * Saves a new tracker in the database. * + * The parameter are given via object deconstruction from the model `Tracker`! + * Currently given parameters are: * @param uid - ID (EUI) of the tracker. * @param vehicleId - assign a vehicle for the tracker. Multiple tracker can have the same vehicle. * @param data - optional additional data field. - * @returns Tracker | null if an error occurs + * @returns Tracker */ - public async save(uid: string, vehicleId?: number | null, data?: any): Promise { - try { - return await this.prisma.tracker.create({ - data: { - uid: uid, - vehicleId: vehicleId, - data: data - } - }) - } catch (e) { - logger.debug(e) - return null - } + public async save(args: Prisma.TrackerUncheckedCreateInput): Promise { + //TrackerUncheckedCreateInput is used because of the relation to vehicles. + return await this.prisma.tracker.create({ + data: args + }) } /** * Updates a tracker in the database. * * @param uid - Indicator which tracker should be updated + * + * The parameter are given via object deconstruction from the model `Tracker`! + * Currently given parameters are: * @param vehicleId - New vehicleId (Optional) * @param data - New additional data field (Optional) - * @returns Tracker | null if an error occurs + * @returns Tracker */ - public async update(uid: string, vehicleId?: number | null, data?: any): Promise { - try { - return await this.prisma.tracker.update({ - where: { - uid: uid - }, - data: { - vehicleId: vehicleId, - data: data - } - }) - } catch (e) { - logger.debug(e) - return null - } + public async update(uid: string, args: Prisma.TrackerUncheckedUpdateInput): Promise { + //TrackerUncheckedUpdateInput is used because of the relation to vehicles. + return await this.prisma.tracker.update({ + where: { + uid: uid + }, + data: args + }) } /** * Removes a tracker from the database. * * @param uid - Indicator which tracker should be removed. - * @returns True | False depending on if the tracker was removed or not. + * @returns True if the removal was successful. Otherwise throws an Error. */ public async remove(uid: string): Promise { - try { - await this.prisma.tracker.delete({ - where: { - uid: uid - } - }) - return true - } catch (e) { - logger.debug(e) - return false - } + await this.prisma.tracker.delete({ + where: { + uid: uid + } + }) + return true } /** @@ -90,12 +74,7 @@ export default class TrackerController { * @returns Tracker[] - List of all trackers. */ public async getAll(): Promise { - try { - return await this.prisma.tracker.findMany({}) - } catch (e) { - logger.debug(e) - return [] - } + return await this.prisma.tracker.findMany({}) } /** @@ -105,16 +84,11 @@ export default class TrackerController { * @returns Tracker | null depending on if the tracker could be found. */ public async getById(uid: string): Promise { - try { - return await this.prisma.tracker.findUnique({ - where: { - uid: uid - } - }) - } catch (e) { - logger.debug(e) - return null - } + return await this.prisma.tracker.findUnique({ + where: { + uid: uid + } + }) } /** @@ -124,15 +98,10 @@ export default class TrackerController { * @returns List of trackers assigned to the vehicle. */ public async getByVehicleId(vehicleId: number): Promise { - try { - return await this.prisma.tracker.findMany({ - where: { - vehicleId: vehicleId - } - }) - } catch (e) { - logger.debug(e) - return [] - } + return await this.prisma.tracker.findMany({ + where: { + vehicleId: vehicleId + } + }) } } diff --git a/Server/src/services/db/user.controller.ts b/Server/src/services/db/user.controller.ts index 820d531b..154d98ae 100644 --- a/Server/src/services/db/user.controller.ts +++ b/Server/src/services/db/user.controller.ts @@ -1,6 +1,4 @@ -import { PrismaClient, Prisma } from "@prisma/client" -import type { User } from "@prisma/client" -import { logger } from "../../utils/logger" +import { PrismaClient, Prisma, User } from "@prisma/client" /** * UserController class @@ -19,67 +17,51 @@ export default class UserController { /** * Saves an user in the database. * + * The parameter are given via object deconstruction from the model `User`! + * Currently given parameters are: * @param username - **unique** name of the user. * @param password - **hashed** password. - * @returns User | null if an error occurs. + * @returns User */ - public async save(username: string, password: string): Promise { - try { - return await this.prisma.user.create({ - data: { - username: username, - password: password - } - }) - } catch (e) { - logger.debug(e) - return null - } + public async save(args: Prisma.UserCreateInput): Promise { + return await this.prisma.user.create({ + data: args + }) } /** * Updates an user in the database. * * @param name - Old username before change. Indicator which user should be updated + * + * The parameter are given via object deconstruction from the model `User`! + * Currently given parameters are: * @param username - New username after change. (Optional) * @param password - New password after change. (Optional) - * @returns User | null if an error occurs. + * @returns User */ - public async update(name: string, username?: string, password?: string): Promise { - try { - return await this.prisma.user.update({ - where: { - username: name - }, - data: { - username: username, - password: password - } - }) - } catch (e) { - logger.debug(e) - return null - } + public async update(name: string, args: Prisma.UserUpdateInput): Promise { + return await this.prisma.user.update({ + where: { + username: name + }, + data: args + }) } /** * Removes an user from the database. * * @param username - Indicator which user should be removed - * @returns True | False depending on if the user was removed or not. + * @returns True if the removal was successful. Otherwise throws an Error. */ - public async remove(username: string): Promise { - try { - await this.prisma.user.delete({ - where: { - username: username - } - }) - return true - } catch (e) { - logger.debug(e) - return false - } + public async remove(username: string): Promise { + await this.prisma.user.delete({ + where: { + username: username + } + }) + return true } /** @@ -88,12 +70,7 @@ export default class UserController { * @returns `User[]` - List of all users. */ public async getAll(): Promise { - try { - return await this.prisma.user.findMany({}) - } catch (e) { - logger.debug(e) - return [] - } + return await this.prisma.user.findMany({}) } /** @@ -103,15 +80,10 @@ export default class UserController { * @returns User | null depending on if the user could be found. */ public async getByUsername(username: string): Promise { - try { - return await this.prisma.user.findUnique({ - where: { - username: username - } - }) - } catch (e) { - logger.debug(e) - return null - } + return await this.prisma.user.findUnique({ + where: { + username: username + } + }) } } diff --git a/Server/src/services/db/vehicle.controller.ts b/Server/src/services/db/vehicle.controller.ts index 54f5ddea..970a42d4 100644 --- a/Server/src/services/db/vehicle.controller.ts +++ b/Server/src/services/db/vehicle.controller.ts @@ -1,302 +1,231 @@ -import { PrismaClient, Prisma } from "@prisma/client" -import type { Vehicle, VehicleType } from "@prisma/client" -import { logger } from "../../utils/logger" - -/** - * VehicleController class - * - * Handles vehicle specific access to the datbase. - * This controller handles therefore Vehicles and VehicleTypes. - * @functions for VehicleTypes: - * - saveType() - * - updateType() - * - removeType() - * - getAllTypes() - * - getTypeById() - * - getTypeByName() - * @functions for Vehicles: - * - save() - * - update() - * - remove() - * - getAll() - * - getById() - * - getByName() - */ -export default class VehicleController { - constructor(private prisma: PrismaClient) {} - - // ========================================================= // - // [Vehicle Types] - - /** - * Saves a vehicle type in the database. - * - * @param name - **unique** Name for the type of vehicle. - * @param icon - unique icon name for visualization - * @param description - optional description for the type. - * @returns VehicleType | null if an error occurs - */ - public async saveType(name: string, icon: string, description?: string): Promise { - try { - return await this.prisma.vehicleType.create({ - data: { - name: name, - icon: icon, - description: description - } - }) - } catch (e) { - logger.debug(e) - return null - } - } - - /** - * Updates a vehicle type in the database. - * - * @param uid - Indicator which vehicle type should be updated. - * @param name - New name of the vehicle type after change. (Optional) - * @param description - New description of the vehicle type after change. (Optional) - * @returns - */ - public async updateType( - uid: number, - name?: string, - icon?: string, - description?: string - ): Promise { - try { - return await this.prisma.vehicleType.update({ - where: { - uid: uid - }, - data: { - name: name, - icon: icon, - description: description - } - }) - } catch (e) { - logger.debug(e) - return null - } - } - - /** - * Removes a vehicle type in the database. - * - * @param uid - Indicator which vehicle type should be removed. - * @returns True | False depending on if the track was removed or not. - */ - public async removeType(uid: number): Promise { - try { - await this.prisma.vehicleType.delete({ - where: { - uid: uid - } - }) - return true - } catch (e) { - logger.debug(e) - return false - } - } - - /** - * Returns a list of all vehicle types. - * - * @returns VehicleType[] - List of all vehicle types. - */ - public async getAllTypes(): Promise { - try { - return await this.prisma.vehicleType.findMany({}) - } catch (e) { - logger.debug(e) - return [] - } - } - - /** - * Looks up a vehicle type given by its uid. - * - * @param uid - Indicator which vehicle type should be searched for. - * @returns VehicleType | null depending on if the vehicle type could be found. - */ - public async getTypeById(uid: number): Promise { - try { - return await this.prisma.vehicleType.findUnique({ - where: { - uid: uid - } - }) - } catch (e) { - logger.debug(e) - return null - } - } - - /** - * Looks up a vehicle type by its name. - * - * @param uid - Indicator which vehicle type should be searched for. - * @returns VehicleType | null depending on if the vehicle type could be found. - */ - public async getTypeByName(name: string): Promise { - try { - return await this.prisma.vehicleType.findUnique({ - where: { - name: name - } - }) - } catch (e) { - logger.debug(e) - return null - } - } - - // ========================================================= // - // [Vehicles] - - /** - * Saves a new vehicle in the database. - * - * @param typeId - VehicleType uid - * @param trackId - Track uid - * @param name - display name for the given vehicle (Optional) - * @returns Vehicle | null if an error occurs. - */ - public async save(typeId: number, trackId: number, name: string): Promise { - try { - return await this.prisma.vehicle.create({ - data: { - name: name, - typeId: typeId, - trackId: trackId - } - }) - } catch (e) { - logger.debug(e) - return null - } - } - - /** - * Updadtes a vehicle in the database. - * - * @param uid - Indicator which vehicle should be updated - * @param typeId - New VehicleType.uid after change (Optional) - * @param trackId - New Track.uid after change (Optional) - * @param name - New display name after change (Optional) - * @returns Vehicle | null if an error occurs - */ - public async update(uid: number, typeId?: number, trackId?: number, name?: string): Promise { - try { - return await this.prisma.vehicle.update({ - where: { - uid: uid - }, - data: { - name: name, - typeId: typeId, - trackId: trackId - } - }) - } catch (e) { - logger.debug(e) - return null - } - } - - /** - * Removes a vehicle in the database. - * - * @param uid - Indicator which vehicle should be removed. - * @returns True | False depending on if the vehicle was removed or not. - */ - public async remove(uid: number): Promise { - try { - await this.prisma.vehicle.delete({ - where: { - uid: uid - } - }) - return true - } catch (e) { - logger.debug(e) - return false - } - } - - /** - * Returns a list of all vehicles. - * - * @param trackId - Track.uid for filtering list (Optional) - * - * @returns Vehicle[] - */ - public async getAll(trackId?: number): Promise { - try { - return await this.prisma.vehicle.findMany({ - where: { - trackId: trackId - }, - include: { - type: true, - track: true - } - }) - } catch (e) { - logger.debug(e) - return [] - } - } - - /** - * Looks up a vehicle by its uid. - * - * @param uid - Indicator which vehicle should be looked for. - * @returns Vehicle | null depending on if the vehicle could be found. - */ - public async getById(uid: number): Promise { - try { - return await this.prisma.vehicle.findUnique({ - where: { - uid: uid - }, - include: { - type: true, - track: true - } - }) - } catch (e) { - logger.debug(e) - return null - } - } - - /** - * Looks up a vehicle by its name. - * - * @param name - Indicator which vehicle should be looked for. - * @returns Vehicle | null depending on if the vehicle could be found. - */ - public async getByName(name: string, trackId: number): Promise { - try { - return await this.prisma.vehicle.findUnique({ - where: { - name_trackId: { - name: name, - trackId: trackId - } - }, - include: { - type: true, - track: true - } - }) - } catch (e) { - logger.debug(e) - return null - } - } -} +import { PrismaClient, Prisma, Vehicle, VehicleType } from "@prisma/client" + +/** + * VehicleController class + * + * Handles vehicle specific access to the datbase. + * This controller handles therefore Vehicles and VehicleTypes. + * @functions for VehicleTypes: + * - saveType() + * - updateType() + * - removeType() + * - getAllTypes() + * - getTypeById() + * - getTypeByName() + * @functions for Vehicles: + * - save() + * - update() + * - remove() + * - getAll() + * - getById() + * - getByName() + */ +export default class VehicleController { + constructor(private prisma: PrismaClient) {} + + // ========================================================= // + // [Vehicle Types] + + /** + * Saves a vehicle type in the database. + * + * The parameter are given via object deconstruction from the model `VehicleType`! + * Currently given parameters are: + * @param name - **unique** Name for the type of vehicle. + * @param icon - unique icon name for visualization + * @param description - optional description for the type. + * @returns VehicleType | null if an error occurs + */ + public async saveType(args: Prisma.VehicleTypeCreateInput): Promise { + return await this.prisma.vehicleType.create({ + data: args + }) + } + + /** + * Updates a vehicle type in the database. + * + * @param uid - Indicator which vehicle type should be updated. + * + * The parameter are given via object deconstruction from the model `VehicleType`! + * Currently given parameters are: + * @param name - New name of the vehicle type after change. (Optional) + * @param description - New description of the vehicle type after change. (Optional) + * @returns + */ + public async updateType(uid: number, args: Prisma.VehicleTypeUpdateInput): Promise { + return await this.prisma.vehicleType.update({ + where: { + uid: uid + }, + data: args + }) + } + + /** + * Removes a vehicle type in the database. + * + * @param uid - Indicator which vehicle type should be removed. + * @returns True if the removal was successful. Otherwise throws an Error. + */ + public async removeType(uid: number): Promise { + await this.prisma.vehicleType.delete({ + where: { + uid: uid + } + }) + return true + } + + /** + * Returns a list of all vehicle types. + * + * @returns VehicleType[] - List of all vehicle types. + */ + public async getAllTypes(): Promise { + return await this.prisma.vehicleType.findMany({}) + } + + /** + * Looks up a vehicle type given by its uid. + * + * @param uid - Indicator which vehicle type should be searched for. + * @returns VehicleType | null depending on if the vehicle type could be found. + */ + public async getTypeById(uid: number): Promise { + return await this.prisma.vehicleType.findUnique({ + where: { + uid: uid + } + }) + } + + /** + * Looks up a vehicle type by its name. + * + * @param uid - Indicator which vehicle type should be searched for. + * @returns VehicleType | null depending on if the vehicle type could be found. + */ + public async getTypeByName(name: string): Promise { + return await this.prisma.vehicleType.findUnique({ + where: { + name: name + } + }) + } + + // ========================================================= // + // [Vehicles] + + /** + * Saves a new vehicle in the database. + * + * The parameter are given via object deconstruction from the model `Vehicle`! + * Currently given parameters are: + * @param typeId - VehicleType uid + * @param trackId - Track uid + * @param name - display name for the given vehicle (Optional) + * @returns Vehicle | null if an error occurs. + */ + public async save(args: Prisma.VehicleUncheckedCreateInput): Promise { + // VehicleUncheckedCreateInput is used because of required relations + return await this.prisma.vehicle.create({ + data: args + }) + } + + /** + * Updadtes a vehicle in the database. + * + * @param uid - Indicator which vehicle should be updated + * + * The parameter are given via object deconstruction from the model `Vehicle`! + * Currently given parameters are: + * @param typeId - New VehicleType.uid after change (Optional) + * @param trackId - New Track.uid after change (Optional) + * @param name - New display name after change (Optional) + * @returns Vehicle | null if an error occurs + */ + public async update(uid: number, args: Prisma.VehicleUncheckedUpdateInput): Promise { + // VehicleUncheckCreateInput is used because of required relations + return await this.prisma.vehicle.update({ + where: { + uid: uid + }, + data: args + }) + } + + /** + * Removes a vehicle in the database. + * + * @param uid - Indicator which vehicle should be removed. + * @returns True if the removal was successful. Otherwise throws an Error. + */ + public async remove(uid: number): Promise { + await this.prisma.vehicle.delete({ + where: { + uid: uid + } + }) + return true + } + + /** + * Returns a list of all vehicles. + * + * @param trackId - Track.uid for filtering list (Optional) + * + * @returns Vehicle[] + */ + public async getAll(trackId?: number): Promise { + return await this.prisma.vehicle.findMany({ + where: { + trackId: trackId + }, + include: { + type: true, + track: true + } + }) + } + + /** + * Looks up a vehicle by its uid. + * + * @param uid - Indicator which vehicle should be looked for. + * @returns Vehicle | null depending on if the vehicle could be found. + */ + public async getById(uid: number): Promise { + return await this.prisma.vehicle.findUnique({ + where: { + uid: uid + }, + include: { + type: true, + track: true + } + }) + } + + /** + * Looks up a vehicle by its name. + * + * @param name - Indicator which vehicle should be looked for. + * @returns Vehicle | null depending on if the vehicle could be found. + */ + public async getByName(name: string, trackId: number): Promise { + return await this.prisma.vehicle.findUnique({ + where: { + name_trackId: { + name: name, + trackId: trackId + } + }, + include: { + type: true, + track: true + } + }) + } +} diff --git a/Server/src/services/login.service.ts b/Server/src/services/login.service.ts index 06ebf7b6..891e8042 100644 --- a/Server/src/services/login.service.ts +++ b/Server/src/services/login.service.ts @@ -51,7 +51,7 @@ export default class LoginService { if (!hashed_pass) { return } - const createdUser: User | null = await database.users.save(auth.username, hashed_pass) + const createdUser: User | null = await database.users.save({ username: auth.username, password: hashed_pass }) if (!createdUser) { return } diff --git a/Server/src/services/poi.service.ts b/Server/src/services/poi.service.ts index 44d5163d..65dc0aae 100644 --- a/Server/src/services/poi.service.ts +++ b/Server/src/services/poi.service.ts @@ -1,4 +1,4 @@ -import { POI, POIType, Track } from ".prisma/client" +import { POI, POIType, Prisma, Track } from ".prisma/client" import database from "./database.service" import TrackService from "./track.service" import GeoJSONUtils from "../utils/geojsonUtils" @@ -43,8 +43,17 @@ export default class POIService { logger.error(`The position ${JSON.stringify(position)} could not be enriched.`) return null } - // typecast to any, because JSON is expected - return database.pois.save(name, type.uid, track.uid, enrichedPoint as any, description, isTurningPoint) + + // Note: geopos is from type GeoJSON.Feature and can't be parsed directly into Prisma.InputJsonValue + // Therefore we cast it into unknown first. + return database.pois.save({ + name, + typeId: type.uid, + trackId: track.uid, + position: enrichedPoint as unknown as Prisma.InputJsonValue, + description: description, + isTurningPoint: isTurningPoint ?? false + }) } /** @@ -117,7 +126,9 @@ export default class POIService { return null } // try to update the poi in the database, now that we have enriched it - if ((await database.pois.update(poi.uid, undefined, undefined, undefined, undefined, enrichedPos)) == null) { + if ( + (await database.pois.update(poi.uid, { position: enrichedPos as unknown as Prisma.InputJsonValue })) == null + ) { logger.info(`Could not update POI with id ${poi.uid} after enriching it.`) } diff --git a/Server/src/services/track.service.ts b/Server/src/services/track.service.ts index 3a57c5cf..74f5bb5d 100644 --- a/Server/src/services/track.service.ts +++ b/Server/src/services/track.service.ts @@ -1,4 +1,4 @@ -import { Track } from ".prisma/client" +import { Prisma, Track } from ".prisma/client" import database from "./database.service" import GeoJSONUtils from "../utils/geojsonUtils" @@ -27,7 +27,9 @@ export default class TrackService { ): Promise { const enrichedTrack = this.enrichTrackData(track) - return database.tracks.save(start, dest, enrichedTrack) + // Note: Based on FeatureCollection it is not possible to cast to Prisma.InputJsonValue directly + // Therefore we cast it into unknown first. (Also recommended by Prisma itself) + return database.tracks.save({ start, stop: dest, data: enrichedTrack as unknown as Prisma.InputJsonValue }) } /** @@ -46,7 +48,13 @@ export default class TrackService { ): Promise { const enrichedTrack = this.enrichTrackData(path) - return database.tracks.update(track.uid, start, dest, enrichedTrack) + // Note: Based on FeatureCollection it is not possible to cast to Prisma.InputJsonValue directly + // Therefore we cast it into unknown first. (Also recommended by Prisma itself) + return database.tracks.update(track.uid, { + start, + stop: dest, + data: enrichedTrack as unknown as Prisma.InputJsonValue + }) } /** diff --git a/Server/src/services/user.service.ts b/Server/src/services/user.service.ts index 3020100f..5b1c629c 100644 --- a/Server/src/services/user.service.ts +++ b/Server/src/services/user.service.ts @@ -28,7 +28,7 @@ export default class UserService { logger.error(`Password could not be hashed`) return null } - const addedUser: User | null = await database.users.save(name, hashed_pass) + const addedUser: User | null = await database.users.save({ username: name, password: hashed_pass }) logger.info(`User ${name} was successfully added`) return addedUser } @@ -54,7 +54,7 @@ export default class UserService { logger.error("Hashing of password was not successful") return false } - const successfulUpdate: User | null = await database.users.update(user.username, undefined, hashedPassword) + const successfulUpdate: User | null = await database.users.update(user.username, { password: hashedPassword }) if (successfulUpdate) { logger.info(`Updated password of user ${username}`) } else { @@ -84,7 +84,9 @@ export default class UserService { return false } - const successfulUpdate: User | null = await database.users.update(user.username, usernameChangeRequest.newUsername) + const successfulUpdate: User | null = await database.users.update(user.username, { + username: usernameChangeRequest.newUsername + }) if (!successfulUpdate) { logger.error(`Updating username of user ${usernameChangeRequest.oldUsername} to new username ${usernameChangeRequest.newUsername} failed`) @@ -113,7 +115,7 @@ export default class UserService { return false } - const successful: Boolean = await database.users.remove(userToBeDeleted.username) + const successful: boolean = await database.users.remove(userToBeDeleted.username) if (!successful.valueOf()) { logger.error(`Could not remove user with username ${name}.`) return false diff --git a/Server/src/services/vehicle.service.ts b/Server/src/services/vehicle.service.ts index 76662c40..d74251b0 100644 --- a/Server/src/services/vehicle.service.ts +++ b/Server/src/services/vehicle.service.ts @@ -171,7 +171,7 @@ export default class VehicleService { // get all vehicles for track and filter by type const vehicles: Vehicle[] = await database.vehicles.getAll(track.uid) - const filteredVehicles = vehicles.filter(function (vehicle, index, vehicles) { + const filteredVehicles = vehicles.filter(function (vehicle, _index, _vehicles) { return vehicle.typeId == type.uid }) return filteredVehicles @@ -241,11 +241,11 @@ export default class VehicleService { } // get app logs from last minute (because they do not have any tracker id, we cannot do it the same way as above) - const appLogs = (await database.logs.getNewestLogs(vehicle.uid, 60)).filter(function (log) { + const appLogs = (await database.logs.getNewestLogs(vehicle.uid, 30)).filter(function (log) { return log.trackerId == null }) // add weight to app logs - const weightedAppLogs = await this.addWeightToLogs(appLogs, lineStringData, 60, 15) + const weightedAppLogs = await this.addWeightToLogs(appLogs, lineStringData, 30, 15, true) if (weightedAppLogs == null) { logger.warn(`Could not add weights to app logs for vehicle with id ${vehicle.uid}.`) } else { @@ -579,7 +579,7 @@ export default class VehicleService { } // get all last known tracker logs - let lastLogs: Log[] = [] + const lastLogs: Log[] = [] for (let i = 0; i < trackers.length; i++) { // get last log entry for this tracker const lastLog = await database.logs.getAll(vehicle.uid, trackers[i].uid, 1) @@ -654,7 +654,7 @@ export default class VehicleService { } // get all last known tracker logs - let lastLogs: Log[] = [] + const lastLogs: Log[] = [] for (let i = 0; i < trackers.length; i++) { // get last log entry for this tracker const lastLog = await database.logs.getAll(vehicle.uid, trackers[i].uid, 1)