diff --git a/packages/api/lib/controllers/boxesController.js b/packages/api/lib/controllers/boxesController.js index 9631655c..67064e62 100644 --- a/packages/api/lib/controllers/boxesController.js +++ b/packages/api/lib/controllers/boxesController.js @@ -70,7 +70,7 @@ const } = require('../helpers/userParamHelpers'), handleError = require('../helpers/errorHandler'), jsonstringify = require('stringify-stream'); -const { findDeviceById } = require('@sensebox/opensensemap-api-models/src/box/box'); +const { findDeviceById, locationsForDevice } = require('@sensebox/opensensemap-api-models/src/box/box'); const { createDevice, findDevices, findTags, updateDevice, findById, generateSketch } = require('@sensebox/opensensemap-api-models/src/device'); const { findByUserId } = require('@sensebox/opensensemap-api-models/src/password'); const { getSensorsWithLastMeasurement } = require('@sensebox/opensensemap-api-models/src/sensor'); @@ -195,8 +195,8 @@ const updateBox = async function updateBox (req, res) { */ const getBoxLocations = async function getBoxLocations (req, res) { try { - const box = await Box.findBoxById(req._userParams.boxId, { onlyLocations: true, lean: false }); - res.send(await box.getLocations(req._userParams)); + const device = await findDeviceById(req._userParams.boxId); + res.send(await locationsForDevice(device, req._userParams)); } catch (err) { return handleError(err); } diff --git a/packages/models/src/box/box.js b/packages/models/src/box/box.js index 28efaf55..480b25a4 100644 --- a/packages/models/src/box/box.js +++ b/packages/models/src/box/box.js @@ -1,6 +1,8 @@ 'use strict'; +const { asc } = require('drizzle-orm'); const { db } = require('../drizzle'); +const { locationTable, deviceToLocationTable, deviceRelations } = require('../../schema/schema'); const { mongoose } = require('../db'), timestamp = require('mongoose-timestamp'), @@ -1001,7 +1003,7 @@ boxSchema.methods.getLocations = function getLocations ({ format, fromDate, toDa ); }); - if (format === 'geojson') { + if (format.toLowerCase() === 'geojson') { const geo = { type: 'Feature', geometry: { type: 'LineString', coordinates: [] }, @@ -1171,8 +1173,49 @@ const findDeviceById = async function findDeviceById (deviceId, { populate = tru return device; }; +const locationsForDevice = async (device, { format, fromDate, toDate }) => { + const end = toDate ? toDate : new Date().toISOString(); + const end48hrsBack = new Date(new Date(end).getTime() - (48 * 60 * 60 * 1000)); + const start = fromDate ? fromDate : end48hrsBack.toISOString(); + + const locationsOfDevice = await db.query.deviceTable.findFirst({ + where: (rel, { eq }) => eq(rel.id, device.id), + with: { + locations: { + where: (rel, { between }) => between(rel.time, start, end), + orderBy: asc(deviceToLocationTable.time), + // pfft: https://github.com/drizzle-team/drizzle-orm/pull/2778 + // cannot include the location column due to this bug... -_- + // Using the workaround below instead + // with: { + // geometry: true + // } + } + } + }); + + const locationIds = locationsOfDevice.locations.map(l => l.locationId); + const workaroundLocations = await db.query.locationTable.findMany({ + where: (table, { inArray }) => inArray(table.id, locationIds) + }); + + if (format.toLowerCase() === 'geojson') { + return { type: 'Feature', geometry: { + type: 'LineString', + coordinates: [...workaroundLocations.map(l => [l.location.x, l.location.y])] + }, properties: { + timestamps: [...locationsOfDevice.locations.map(l => l.time)] + } }; + } + + return workaroundLocations.map(entry => { + return { coordinates: [entry.location.x, entry.location.y], type: 'Point', timestamp: locationsOfDevice.locations.find(l => l.locationId === entry.id).time }; + }); +}; + module.exports = { schema: boxSchema, model: boxModel, - findDeviceById + findDeviceById, + locationsForDevice };