Skip to content

Feat/optimize device loading - #1107

Open
jona159 wants to merge 4 commits into
devfrom
feat/optimize-device-loading
Open

jona159 wants to merge 4 commits into
devfrom
feat/optimize-device-loading

Conversation

@jona159

@jona159 jona159 commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Type of Change

  • Dependency upgrade
  • Bug fix (non-breaking change)
  • Breaking change
    • e.g. a fixed bug or new feature that may break something else
  • New feature
  • Code quality improvements
    • e.g. refactoring, documentation, tests, tooling, ...

Implementation

Checklist

  • I gave this pull request a meaningful title
  • My pull request is targeting the dev branch
  • I have added documentation to my code
  • I have deleted code that I have commented out

Additional Information

  • This PR closes #

@coderabbitai

coderabbitai Bot commented Sep 18, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 671521b9-45c8-4ec9-af8f-b0ab7e3c77dc

📝 Summary

Summary by CodeRabbit

  • New Features

    • Mobile devices in Explore now display location history alongside their latest sensor measurements.
    • Location history is ordered from newest to oldest and includes map coordinates for each recorded position.
  • Bug Fixes

    • Devices without mobile exposure no longer receive location data in Explore, keeping displayed information relevant to the device type.

Walkthrough

The device model separates general device data from location history. The explore loader loads locations only for mobile devices while fetching sensor measurements concurrently. A test verifies that getDevice excludes locations.

Changes

Device location flow

Layer / File(s) Summary
Separate device and location queries
app/db/models/device.server.ts
getDevice no longer loads location history. The new getDeviceLocations function returns locations ordered by descending timestamp with extracted coordinates.
Conditional loader integration and validation
app/routes/explore.$deviceId.tsx, tests/db/models/device.server.spec.ts
The loader fetches the device and sensor measurements concurrently. It loads locations for mobile devices and uses an empty array for other devices. A test verifies that getDevice has no locations property.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ExploreLoader
  participant getDevice
  participant SensorMeasurements
  participant getDeviceLocations
  ExploreLoader->>getDevice: fetch device
  ExploreLoader->>SensorMeasurements: fetch latest measurements
  getDevice-->>ExploreLoader: device exposure
  alt mobile exposure
    ExploreLoader->>getDeviceLocations: fetch locations
    getDeviceLocations-->>ExploreLoader: ordered locations
  end
  ExploreLoader-->>ExploreLoader: attach locations to device result
Loading

Merge Risk: 🔵 Low · up to 039bf

Mobile explore pages can incur avoidable latency when sensor retrieval is slow, and location-history output changes could regress without test detection. These are bounded concerns and can be addressed as follow-up work.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description contains only an uncompleted template and does not provide implementation details or a meaningful summary of the changes. Add a concise description of the device loading optimization, including the separate location query for mobile devices and the related test coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: optimizing device loading by separating device location retrieval.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Sep 18, 2026

Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 66.58% 2357 / 3540
🔵 Statements 65.02% 2434 / 3743
🔵 Functions 63.39% 452 / 713
🔵 Branches 51.72% 1154 / 2231
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
app/db/models/device.server.ts 62.31% 68.01% 57.4% 63.56% 96-101, 109, 196, 208-209, 249-263, 293-332, 368, 429, 463, 498, 523, 537, 567, 571, 579-581, 587-589, 607-609, 613-615, 662-664, 679, 700-899, 950-954, 982-988, 993-1009, 1096-1098, 1109, 1116-1117, 1129-1136, 1140-1151, 1197, 1305-1325, 1344
Generated in workflow #3067 for commit 63492fe by the Vitest Coverage Report Action

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 27487f93-fa0f-486d-9aa3-e15f61563bc7

📥 Commits

Reviewing files that changed from the base of the PR and between 4f3c707 and 039bf92.

📒 Files selected for processing (3)
  • app/db/models/device.server.ts
  • app/routes/explore.$deviceId.tsx
  • tests/db/models/device.server.spec.ts

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment on lines 239 to 262
)
.orderBy(desc(deviceToLocation.time))
}

export async function getDeviceLocations({ id }: Pick<Device, 'id'>) {
const locations = await drizzleClient
.select({
time: deviceToLocation.time,
x: sql<number>`ST_X(${location.location})`.as('x'),
y: sql<number>`ST_Y(${location.location})`.as('y'),
})
.from(location)
.innerJoin(deviceToLocation, eq(deviceToLocation.locationId, location.id))
.where(eq(deviceToLocation.deviceId, id))
.orderBy(desc(deviceToLocation.time))

return locations.map(({ time, x, y }) => ({
time,
geometry: { x, y },
}))
}
export function getDeviceWithoutSensors({ id }: Pick<Device, 'id'>) {
return drizzleClient.query.device.findFirst({
where: (device, { eq }) => eq(device.id, id),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

sed -n '100,155p' tests/db/models/device.server.spec.ts
sed -n '230,275p' app/db/models/device.server.ts
rg -n -A30 -B10 'getDeviceLocations|locations.*geometry|geometry.*locations|location history' app tests

Repository: openSenseMap/frontend

Length of output: 21698


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- device model test outline/imports/location references ---'
ast-grep outline tests/db/models/device.server.spec.ts
sed -n '1,45p' tests/db/models/device.server.spec.ts
rg -n -A18 -B8 'location|Locations|getDeviceLocations' tests/db/models/device.server.spec.ts

printf '%s\n' '--- route location test structure and imports ---'
sed -n '1,115p' tests/routes/api.location.spec.ts
rg -n -A45 -B12 'getDeviceLocations|locations\)\.to|locations\)\.toEqual|coordinates' tests/routes/api.location.spec.ts

printf '%s\n' '--- focused diff metadata ---'
git diff --stat -- tests/db/models/device.server.spec.ts tests/routes/api.location.spec.ts app/db/models/device.server.ts app/routes/explore.\$deviceId.tsx
git status --short

Repository: openSenseMap/frontend

Length of output: 20773


🏁 Script executed:

#!/bin/bash
set -e
sed -n '1,45p' tests/db/models/device.server.spec.ts
rg -n -A18 -B8 'location|Locations|getDeviceLocations' tests/db/models/device.server.spec.ts
sed -n '1,115p' tests/routes/api.location.spec.ts
rg -n -A45 -B12 'getDeviceLocations|locations\)\.to|coordinates' tests/routes/api.location.spec.ts
git diff --stat -- tests/db/models/device.server.spec.ts tests/routes/api.location.spec.ts app/db/models/device.server.ts 'app/routes/explore.$deviceId.tsx'
git status --short

Repository: openSenseMap/frontend

Length of output: 20562


Add a focused getDeviceLocations test.

No existing test calls the production helper. The model test only checks that getDevice omits locations, and the route test uses a separate local query helper.

Add a model or route test that creates multiple locations and asserts the complete { time, geometry: { x, y } } result, descending order, and coordinate values. The mobile explore loader consumes this data for trip grouping and map output, so these regressions can pass without detection.

Comment thread app/routes/explore.$deviceId.tsx Outdated
Comment on lines +22 to +25
const [loadedDevice, sensorsWithLastestMeasurement] = await Promise.all([
getDevice({ id: params.deviceId }),
getSensorsWithLastMeasurement(params.deviceId),
])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

sed -n '1,80p' 'app/routes/explore.$deviceId.tsx'
sed -n '90,140p' app/db/models/device.server.ts
sed -n '230,275p' app/db/models/device.server.ts
rg -n -A45 -B5 'function getSensorsWithLastMeasurement|const getSensorsWithLastMeasurement|export.*getSensorsWithLastMeasurement' app/db/models/sensor.server.ts

Repository: openSenseMap/frontend

Length of output: 7527


Overlap the mobile location query with the sensor query.

The loader starts getSensorsWithLastMeasurement and getDevice together, but it starts getDeviceLocations only after both resolve. getDeviceLocations only requires the device ID, while the exposure check requires only getDevice. When the sensor query outlasts getDevice, this sequencing can extend mobile loader latency by up to the location-query duration. The delay is conditional, so this is a bounded optimization rather than a guaranteed regression.

Start the sensor promise before awaiting the device. Then start the location promise after the device resolves and await both promises together.

Proposed change
-	const [loadedDevice, sensorsWithLastestMeasurement] = await Promise.all([
-		getDevice({ id: params.deviceId }),
-		getSensorsWithLastMeasurement(params.deviceId),
-	])
-	const locations =
+	const loadedDevicePromise = getDevice({ id: params.deviceId })
+	const sensorsPromise = getSensorsWithLastMeasurement(params.deviceId)
+	const loadedDevice = await loadedDevicePromise
+	const locationsPromise =
 		loadedDevice?.exposure === 'mobile'
-			? await getDeviceLocations({ id: params.deviceId })
-			: []
+			? getDeviceLocations({ id: params.deviceId })
+			: Promise.resolve([])
+	const [sensorsWithLastestMeasurement, locations] = await Promise.all([
+		sensorsPromise,
+		locationsPromise,
+	])
 	const device = loadedDevice ? { ...loadedDevice, locations } : loadedDevice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant