Skip to content
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

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
Loading