Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Matched captures statistic #73

Merged
merged 7 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion __tests__/integration/capture_denormalized.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ describe('capture_denormalized', () => {
'species',
'captures',
'unverified_captures',
'matched_captures',
'top_planters',
'trees_per_planters',
'last_updated_at',
Expand All @@ -381,6 +382,7 @@ describe('capture_denormalized', () => {
'total',
'unverified_captures',
]);
expect(res.body.matched_captures).to.have.keys(['total', 'matched_captures']);
expect(res.body.top_planters).to.have.keys([
'average',
'top_planters',
Expand All @@ -396,6 +398,7 @@ describe('capture_denormalized', () => {
checkObjectProperties(
res.body.unverified_captures.unverified_captures,
);
checkObjectProperties(res.body.matched_captures.matched_captures);
checkObjectProperties(res.body.top_planters.top_planters);
checkObjectProperties(res.body.trees_per_planters.trees_per_planters);
checkObjectProperties(res.body.catchments.catchments);
Expand Down Expand Up @@ -426,7 +429,7 @@ describe('capture_denormalized', () => {
.end(function (err, res) {
if (err) return done(err);
expect(res.body.message).to.eql(
'"card_title" must be one of [planters, species, captures, unverified_captures, top_planters, trees_per_planters, catchments, gender_details, approval_rates]',
'"card_title" must be one of [planters, species, captures, unverified_captures, matched_captures, top_planters, trees_per_planters, catchments, gender_details, approval_rates]',
);
return done();
});
Expand Down
53 changes: 53 additions & 0 deletions database/migrations/20230724231226-add-tree-id-column.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
'use strict';

var dbm;
var type;
var seed;
var fs = require('fs');
var path = require('path');
var Promise;

/**
* We receive the dbmigrate dependency from dbmigrate initially.
* This enables us to not have to rely on NODE_PATH.
*/
exports.setup = function(options, seedLink) {
dbm = options.dbmigrate;
type = dbm.dataType;
seed = seedLink;
Promise = options.Promise;
};

exports.up = function(db) {
var filePath = path.join(__dirname, 'sqls', '20230724231226-add-tree-id-column-up.sql');
return new Promise( function( resolve, reject ) {
fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
if (err) return reject(err);
console.log('received data: ' + data);

resolve(data);
});
})
.then(function(data) {
return db.runSql(data);
});
};

exports.down = function(db) {
var filePath = path.join(__dirname, 'sqls', '20230724231226-add-tree-id-column-down.sql');
return new Promise( function( resolve, reject ) {
fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
if (err) return reject(err);
console.log('received data: ' + data);

resolve(data);
});
})
.then(function(data) {
return db.runSql(data);
});
};

exports._meta = {
"version": 1
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE capture_denormalized DROP COLUMN tree_id;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE capture_denormalized ADD COLUMN tree_id uuid;
1 change: 1 addition & 0 deletions server/handlers/captureHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const captureStatisticsGetCardQuerySchema = Joi.object({
'species',
'captures',
'unverified_captures',
'matched_captures',
'top_planters',
'trees_per_planters',
'catchments',
Expand Down
17 changes: 17 additions & 0 deletions server/models/Capture.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ class Capture {
topCatchment = [],
genderCount = [],
approvalRates,
totalMatchedCaptures = undefined,
topMatchedCaptures = [],
}) {
const planters = {
total: totalGrowers,
Expand Down Expand Up @@ -170,11 +172,22 @@ class Capture {
};
});

const matched_captures = {
total: totalMatchedCaptures,
matched_captures: topMatchedCaptures.map(({ planting_organization_name, count }) => {
return {
name: planting_organization_name,
number: count,
}
})
}

return {
planters,
species,
captures,
unverified_captures,
matched_captures,
top_planters,
trees_per_planters,
last_updated_at,
Expand Down Expand Up @@ -203,6 +216,8 @@ class Capture {
topCatchment,
genderCount,
approvalRates,
totalMatchedCaptures,
topMatchedCaptures,
} = await this._captureRepository.getStatistics(filter);

return this.constructor.generateFormattedResponse({
Expand All @@ -223,6 +238,8 @@ class Capture {
topCatchment,
genderCount,
approvalRates,
totalMatchedCaptures,
topMatchedCaptures,
});
}

Expand Down
46 changes: 37 additions & 9 deletions server/repositories/CaptureRepository.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ const BaseRepository = require('./BaseRepository');

class CaptureRepository extends BaseRepository {
constructor(session) {
super('capture_denormalized', session);
this._tableName = 'capture_denormalized';
super('reporting.capture_denormalized', session);
Copy link
Collaborator

Choose a reason for hiding this comment

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

You should remove the 'reporting.'. In the cloud, the DATABASE_URL is already configured only to access the reporting schema, so this is unnecessary. This might also be the reason for the failed tests

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, my bad. I thought I committed the code without the reporting. prefix.

this._tableName = 'reporting.capture_denormalized';
this._session = session;
}

Expand Down Expand Up @@ -55,6 +55,7 @@ class CaptureRepository extends BaseRepository {
const whereBuilder = function (object, builder) {
const result = builder;
const filterObject = { ...object };
console.log('FILTEROBJ', filterObject)
Copy link
Collaborator

Choose a reason for hiding this comment

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

you can remove the console.log

delete filterObject.card_title;
if (filterObject.capture_created_start_date) {
result.where(
Expand Down Expand Up @@ -131,7 +132,7 @@ class CaptureRepository extends BaseRepository {
'planter_last_name',
'planter_identifier',
)
.from('capture_denormalized')
.from('reporting.capture_denormalized')
.where((builder) => whereBuilder(filter, builder))
.as('planters');
});
Expand All @@ -147,7 +148,7 @@ class CaptureRepository extends BaseRepository {
'planting_organization_name',
'planting_organization_uuid',
)
.from('capture_denormalized')
.from('reporting.capture_denormalized')
.where((builder) => whereBuilder(filter, builder))
.groupBy(
'planting_organization_uuid',
Expand Down Expand Up @@ -177,7 +178,7 @@ class CaptureRepository extends BaseRepository {
.avg('totalPlanters')
.from(function () {
this.count('* as totalPlanters')
.from('capture_denormalized')
.from('reporting.capture_denormalized')
.where((builder) => whereBuilder(filter, builder))
.groupBy(
'planter_first_name',
Expand Down Expand Up @@ -236,7 +237,7 @@ class CaptureRepository extends BaseRepository {
`count(*) as count, planting_organization_name, planting_organization_uuid`,
),
)
.from('capture_denormalized')
.from('reporting.capture_denormalized')
.where((builder) => whereBuilder(filter, builder))
.groupBy(
'planting_organization_uuid',
Expand Down Expand Up @@ -265,7 +266,7 @@ class CaptureRepository extends BaseRepository {
`count(*) as count, planting_organization_name, planting_organization_uuid`,
),
)
.from('capture_denormalized')
.from('reporting.capture_denormalized')
.where((builder) => whereBuilder(filter, builder))
.groupBy(
'planting_organization_uuid',
Expand All @@ -287,7 +288,7 @@ class CaptureRepository extends BaseRepository {
.avg('totalCatchment')
.from(function () {
this.count('* as totalCatchment')
.from('capture_denormalized')
.from('reporting.capture_denormalized')
.where((builder) => cachmentWhereBuilder(filter, builder))
.groupBy('catchment')
.as('catchments');
Expand All @@ -312,7 +313,7 @@ class CaptureRepository extends BaseRepository {
'gender',
)
.where((builder) => whereBuilder(filter, builder))
.from('capture_denormalized')
.from('reporting.capture_denormalized')
.as('planters');
})
.groupBy('gender')
Expand Down Expand Up @@ -363,6 +364,24 @@ class CaptureRepository extends BaseRepository {
.limit(options.limit)
.offset(options.offset);


// total number of matched captures
const totalMatchedCapturesQuery = knex(this._tableName)
.count()
.whereNotNull('tree_id')
.where((builder) => whereBuilder({ ...filter, approved: true }, builder));

// top matched captures (by organization)
const topMatchedCapturesQuery = knex(this._tableName)
.select(knex.raw('planting_organization_name, count(*) as count'))
.whereNotNull('tree_id')
.where((builder) => whereBuilder({ ...filter, approved: true }, builder))
.groupBy('planting_organization_uuid', 'planting_organization_name')
.orderBy('count', 'desc')
.limit(options.limit)
.offset(options.offset);


if (filter?.card_title) {
const { card_title } = filter;

Expand All @@ -385,6 +404,7 @@ class CaptureRepository extends BaseRepository {
await topUnverifiedCapturesQuery.cache();
return { topUnverifiedCaptures };
}

case 'top_planters': {
const topPlanters = await topPlantersQuery.cache();
return { topPlanters };
Expand All @@ -402,6 +422,10 @@ class CaptureRepository extends BaseRepository {
const approvalRates = await approvalRateQuery.cache();
return { approvalRates };
}
case 'matched_captures': {
const topMatchedCaptures = await topMatchedCapturesQuery.cache();
return { topMatchedCaptures };
}

default:
break;
Expand Down Expand Up @@ -429,6 +453,8 @@ class CaptureRepository extends BaseRepository {
const topCatchment = await topCatchmentQuery.cache();
const genderCount = await genderCountQuery.cache();
const approvalRates = await approvalRateQuery.cache();
const totalMatchedCaptures = await totalMatchedCapturesQuery.cache();
const topMatchedCaptures = await topMatchedCapturesQuery.cache();

return {
totalGrowers: +totalGrowers[0].totalPlanters,
Expand All @@ -449,6 +475,8 @@ class CaptureRepository extends BaseRepository {
topCatchment,
genderCount,
approvalRates,
totalMatchedCaptures: +totalMatchedCaptures[0].count,
topMatchedCaptures,
};
}
}
Expand Down