-
Notifications
You must be signed in to change notification settings - Fork 22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
first version of the averages API #3762
Changes from all commits
f5a1cec
2b66524
717ea45
96aaa68
a5c479c
6aeb430
8f39c49
b509086
a8180e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -938,6 +938,58 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
listReadingAverages: async (req, res, next) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const errors = extractErrorsFromRequest(req); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (errors) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
next( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
new HttpError("bad request errors", httpStatus.BAD_REQUEST, errors) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const request = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
...req, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
query: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
...req.query, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tenant: isEmpty(req.query.tenant) ? "airqo" : req.query.tenant, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
averages: "readings", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const result = await createEventUtil.listReadingAverages(request, next); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (isEmpty(result) || res.headersSent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const status = result.status || httpStatus.OK; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (result.success === true) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.status(status).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
success: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
message: result.message, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
measurements: result.data, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const errorStatus = result.status || httpStatus.INTERNAL_SERVER_ERROR; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.status(errorStatus).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
success: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
errors: result.errors || { message: "" }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
message: result.message, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
logger.error(`🐛🐛 Internal Server Error ${error.message}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
next( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
new HttpError( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"Internal Server Error", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
httpStatus.INTERNAL_SERVER_ERROR, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ message: error.message } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+941
to
+992
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add unit tests for the new The new endpoint lacks test coverage, which is crucial for ensuring reliability and preventing regressions. Consider adding tests that cover:
Would you like me to help create a test suite for this endpoint? 🧰 Tools🪛 GitHub Check: codecov/patch
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
signalsForMap: async (req, res, next) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
logText("the signals for the AirQo Map..."); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -1195,6 +1247,90 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
listAverages: async (req, res, next) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const errors = extractErrorsFromRequest(req); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (errors) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
next( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
new HttpError("bad request errors", httpStatus.BAD_REQUEST, errors) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const request = req; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const defaultTenant = constants.DEFAULT_TENANT || "airqo"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
request.query.tenant = isEmpty(req.query.tenant) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
? defaultTenant | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
: req.query.tenant; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
request.query.recent = "no"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
request.query.metadata = "site_id"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
request.query.averages = "events"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
request.query.brief = "yes"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { cohort_id, grid_id } = { ...req.query, ...req.params }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+1250
to
+1270
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider centralizing the default tenant configuration. The default tenant value "airqo" is duplicated across multiple controller methods. Consider moving this to a single configuration constant to improve maintainability. -const defaultTenant = constants.DEFAULT_TENANT || "airqo";
+const { DEFAULT_TENANT: defaultTenant = "airqo" } = constants; 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let locationErrors = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (cohort_id) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await processCohortIds(cohort_id, request); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (isEmpty(request.query.device_id)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
locationErrors++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else if (grid_id) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
await processGridIds(grid_id, request); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (isEmpty(request.query.site_id)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
locationErrors++; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+1271
to
+1284
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider refactoring location processing logic. The location processing logic (handling cohort_id and grid_id) is duplicated across multiple methods in this controller. Consider extracting it into a shared utility function. Create a shared utility function: +const processLocationIds = async (request, { cohort_id, grid_id }) => {
+ let locationErrors = 0;
+
+ if (cohort_id) {
+ await processCohortIds(cohort_id, request);
+ if (isEmpty(request.query.device_id)) {
+ locationErrors++;
+ }
+ } else if (grid_id) {
+ await processGridIds(grid_id, request);
+ if (isEmpty(request.query.site_id)) {
+ locationErrors++;
+ }
+ }
+
+ return locationErrors;
+};
listAverages: async (req, res, next) => {
try {
// ... existing setup code ...
- let locationErrors = 0;
- if (cohort_id) {
- await processCohortIds(cohort_id, request);
- if (isEmpty(request.query.device_id)) {
- locationErrors++;
- }
- } else if (grid_id) {
- await processGridIds(grid_id, request);
- if (isEmpty(request.query.site_id)) {
- locationErrors++;
- }
- }
+ const locationErrors = await processLocationIds(request, { cohort_id, grid_id });
🧰 Tools🪛 GitHub Check: codecov/patch
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Create a Github issue for this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Baalmart, I've created a GitHub issue to track this refactoring suggestion: Issue #3779. 🔗 Analysis chain🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Create a new GitHub issue for refactoring the location processing logic
gh issue create \
--title "Refactor location processing logic in create-event.js" \
--body "As discussed in [PR #3762](https://github.com/airqo-platform/AirQo-api/pull/3762), the location processing logic for handling \`cohort_id\` and \`grid_id\` is duplicated across multiple methods in \`src/device-registry/controllers/create-event.js\`. Extracting this logic into a shared utility function would improve code maintainability and reduce redundancy.
This issue was requested by @Baalmart in [this comment](https://github.com/airqo-platform/AirQo-api/pull/3762#discussion_r1816465509)." \
--assignee "Baalmart"
Length of output: 657 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (locationErrors === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const result = await createEventUtil.listAverages(request, next); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (isEmpty(result) || res.headersSent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (result.success === true) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const status = result.status ? result.status : httpStatus.OK; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.status(status).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
success: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
isCache: result.isCache, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
message: result.message, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
measurements: result.data, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else if (result.success === false) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const status = result.status | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
? result.status | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
: httpStatus.INTERNAL_SERVER_ERROR; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const errors = result.errors ? result.errors : { message: "" }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.status(status).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
success: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
errors, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
message: result.message, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
res.status(httpStatus.BAD_REQUEST).json({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
success: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
errors: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
message: `Unable to process measurements for the provided measurement IDs`, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
message: "Bad Request", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
logger.error(`🐛🐛 Internal Server Error ${error.message}`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
next( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
new HttpError( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
"Internal Server Error", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
httpStatus.INTERNAL_SERVER_ERROR, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ message: error.message } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+1250
to
+1333
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add unit tests for the new The new endpoint requires test coverage to ensure proper functionality. Consider adding tests that cover:
Would you like me to help create a test suite for this endpoint? 🧰 Tools🪛 GitHub Check: codecov/patch
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
listHistorical: async (req, res, next) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const errors = extractErrorsFromRequest(req); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -2541,6 +2541,135 @@ | |||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
eventSchema.statics.getAirQualityAverages = async function(siteId, next) { | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove the Including Apply this diff to refactor the method signature: -eventSchema.statics.getAirQualityAverages = async function(siteId, next) {
+eventSchema.statics.getAirQualityAverages = async function(siteId) { 📝 Committable suggestion
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. generate a Github issue for this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Baalmart, thank you for creating the GitHub issue. This will help address the refactoring suggestion. (^.^)/ 🔗 Analysis chain@Baalmart, I've prepared a GitHub issue for this. 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
gh issue create \
--title "Refactor getAirQualityAverages method to remove unnecessary 'next' parameter" \
--body "There's an issue with the static method \`getAirQualityAverages\` in \`eventSchema\`. Including the \`next\` parameter in this method is unconventional for Mongoose models. It's recommended to handle errors by throwing them, allowing the caller to manage error propagation.
Refer to this PR: https://github.com/airqo-platform/AirQo-api/pull/3762
Refer to the comment: https://github.com/airqo-platform/AirQo-api/pull/3762#discussion_r1816358012
Requested by: @Baalmart" \
--assignee Baalmart
Length of output: 667 |
||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||
// Get current date and date 2 weeks ago | ||||||||||||||||||||||||||||||||||
const now = new Date(); | ||||||||||||||||||||||||||||||||||
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); | ||||||||||||||||||||||||||||||||||
const twoWeeksAgo = new Date(today); | ||||||||||||||||||||||||||||||||||
twoWeeksAgo.setDate(today.getDate() - 14); | ||||||||||||||||||||||||||||||||||
Comment on lines
+2547
to
+2550
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve date calculation logic for better accuracy The current date calculation logic could be improved for better accuracy and clarity. Apply this diff to improve the date calculations: -const now = new Date();
-const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
-const twoWeeksAgo = new Date(today);
-twoWeeksAgo.setDate(today.getDate() - 14);
+const now = new Date();
+const today = new Date(now.setHours(0, 0, 0, 0));
+const twoWeeksAgo = new Date(today.getTime() - (14 * 24 * 60 * 60 * 1000)); This change:
📝 Committable suggestion
Suggested change
🧰 Tools🪛 GitHub Check: codecov/patch
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Create a Github issue for this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Baalmart, I've created the GitHub issue as requested: #3778. 🔗 Analysis chain@Baalmart, I'll create a GitHub issue for this. 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
gh issue create \
--title "Improve date calculation logic for better accuracy" \
--body "As discussed in [PR #3762](https://github.com/airqo-platform/AirQo-api/pull/3762), it's suggested to improve the date calculation logic for better accuracy.\n\nRequester: @Baalmart\n\nRelated comment: [Link to the comment](https://github.com/airqo-platform/AirQo-api/pull/3762#discussion_r1816465498)" \
--assignee Baalmart
Length of output: 467 |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// Base query to match site and time range | ||||||||||||||||||||||||||||||||||
const baseMatch = { | ||||||||||||||||||||||||||||||||||
"values.site_id": mongoose.Types.ObjectId(siteId), | ||||||||||||||||||||||||||||||||||
"values.time": { | ||||||||||||||||||||||||||||||||||
$gte: twoWeeksAgo, | ||||||||||||||||||||||||||||||||||
$lte: now, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
const result = await this.aggregate([ | ||||||||||||||||||||||||||||||||||
// Unwind the values array to work with individual readings | ||||||||||||||||||||||||||||||||||
{ $unwind: "$values" }, | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// Match site and time range | ||||||||||||||||||||||||||||||||||
{ $match: baseMatch }, | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// Project only needed fields and add date fields for grouping | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
$project: { | ||||||||||||||||||||||||||||||||||
time: "$values.time", | ||||||||||||||||||||||||||||||||||
pm2_5: "$values.pm2_5.value", | ||||||||||||||||||||||||||||||||||
dayOfYear: { $dayOfYear: "$values.time" }, | ||||||||||||||||||||||||||||||||||
year: { $year: "$values.time" }, | ||||||||||||||||||||||||||||||||||
week: { $week: "$values.time" }, | ||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use The Apply this diff to update the operator: -week: { $week: "$values.time" },
+week: { $isoWeek: "$values.time" }, 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// Group by day to get daily averages | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
$group: { | ||||||||||||||||||||||||||||||||||
_id: { | ||||||||||||||||||||||||||||||||||
year: "$year", | ||||||||||||||||||||||||||||||||||
dayOfYear: "$dayOfYear", | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
dailyAverage: { $avg: "$pm2_5" }, | ||||||||||||||||||||||||||||||||||
date: { $first: "$time" }, | ||||||||||||||||||||||||||||||||||
week: { $first: "$week" }, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// Sort by date | ||||||||||||||||||||||||||||||||||
{ $sort: { date: -1 } }, | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// Group again to calculate weekly averages | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
$group: { | ||||||||||||||||||||||||||||||||||
_id: "$week", | ||||||||||||||||||||||||||||||||||
weeklyAverage: { $avg: "$dailyAverage" }, | ||||||||||||||||||||||||||||||||||
days: { | ||||||||||||||||||||||||||||||||||
$push: { | ||||||||||||||||||||||||||||||||||
date: "$date", | ||||||||||||||||||||||||||||||||||
average: "$dailyAverage", | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// Sort by week | ||||||||||||||||||||||||||||||||||
{ $sort: { _id: -1 } }, | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// Limit to get only last 2 weeks | ||||||||||||||||||||||||||||||||||
{ $limit: 2 }, | ||||||||||||||||||||||||||||||||||
]).allowDiskUse(true); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// If we don't have enough data | ||||||||||||||||||||||||||||||||||
if (result.length < 2) { | ||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||
success: false, | ||||||||||||||||||||||||||||||||||
message: "Insufficient data for comparison", | ||||||||||||||||||||||||||||||||||
status: httpStatus.NOT_FOUND, | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// Get current week and previous week data | ||||||||||||||||||||||||||||||||||
const currentWeek = result[0]; | ||||||||||||||||||||||||||||||||||
const previousWeek = result[1]; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// Calculate percentage difference | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
const percentageDifference = | ||||||||||||||||||||||||||||||||||
previousWeek.weeklyAverage !== 0 | ||||||||||||||||||||||||||||||||||
? ((currentWeek.weeklyAverage - previousWeek.weeklyAverage) / | ||||||||||||||||||||||||||||||||||
previousWeek.weeklyAverage) * | ||||||||||||||||||||||||||||||||||
100 | ||||||||||||||||||||||||||||||||||
: 0; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// Get today's date string in YYYY-MM-DD format | ||||||||||||||||||||||||||||||||||
const todayStr = today.toISOString().split("T")[0]; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// Find today's average from the current week's days | ||||||||||||||||||||||||||||||||||
const todayAverage = | ||||||||||||||||||||||||||||||||||
currentWeek.days.find( | ||||||||||||||||||||||||||||||||||
(day) => day.date.toISOString().split("T")[0] === todayStr | ||||||||||||||||||||||||||||||||||
)?.average || null; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
return { | ||||||||||||||||||||||||||||||||||
success: true, | ||||||||||||||||||||||||||||||||||
data: { | ||||||||||||||||||||||||||||||||||
dailyAverage: todayAverage ? parseFloat(todayAverage.toFixed(2)) : null, | ||||||||||||||||||||||||||||||||||
percentageDifference: parseFloat(percentageDifference.toFixed(2)), | ||||||||||||||||||||||||||||||||||
weeklyAverages: { | ||||||||||||||||||||||||||||||||||
currentWeek: parseFloat(currentWeek.weeklyAverage.toFixed(2)), | ||||||||||||||||||||||||||||||||||
previousWeek: parseFloat(previousWeek.weeklyAverage.toFixed(2)), | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||
message: "Successfully retrieved air quality averages", | ||||||||||||||||||||||||||||||||||
status: httpStatus.OK, | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
} catch (error) { | ||||||||||||||||||||||||||||||||||
logger.error( | ||||||||||||||||||||||||||||||||||
`Internal Server Error --- getAirQualityAverages --- ${error.message}` | ||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||
logObject("error", error); | ||||||||||||||||||||||||||||||||||
next( | ||||||||||||||||||||||||||||||||||
new HttpError("Internal Server Error", httpStatus.INTERNAL_SERVER_ERROR, { | ||||||||||||||||||||||||||||||||||
message: error.message, | ||||||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
Comment on lines
+2662
to
+2670
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Refactor error handling to throw errors instead of calling Within model methods, throwing errors is preferred over calling Apply this diff to update the error handling: logger.error(
`Internal Server Error --- getAirQualityAverages --- ${error.message}`
);
logObject("error", error);
- next(
- new HttpError("Internal Server Error", httpStatus.INTERNAL_SERVER_ERROR, {
+ throw new HttpError("Internal Server Error", httpStatus.INTERNAL_SERVER_ERROR, {
message: error.message,
})
- ); 📝 Committable suggestion
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please create a Github issue for this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Baalmart, the GitHub issue has been successfully created: #3769. 🔗 Analysis chain@Baalmart, I'll create a GitHub issue for this as requested. 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Creating a new GitHub issue for refactoring error handling in getAirQualityAverages method
gh issue create \
--title "Refactor error handling in getAirQualityAverages method" \
--body "Within the \`getAirQualityAverages\` method in \`src/device-registry/models/Event.js\`, refactor the error handling to throw errors instead of calling \`next\`. This issue was raised during code review at [this comment](https://github.com/airqo-platform/AirQo-api/pull/3762#discussion_r1816358022) in [PR #3762](https://github.com/airqo-platform/AirQo-api/pull/3762). Requested by @Baalmart." \
--assignee Baalmart
Length of output: 554 |
||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
const eventsModel = (tenant) => { | ||||||||||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||||||||||
const events = mongoose.model("events"); | ||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add unit tests for
listReadingAverages
to improve code coverage.The new method
listReadingAverages
is not currently covered by unit tests, as indicated by the static analysis tools. Implementing unit tests will help ensure the method functions correctly and maintain code reliability.🧰 Tools
🪛 GitHub Check: codecov/patch