@hestia-earth/data-api 0.0.2-3 → 0.0.2-5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/aggregated-nodes/model/index.d.ts +42 -5
  2. package/package.json +2 -2
  3. package/.dockerignore +0 -25
  4. package/.env.test +0 -7
  5. package/.eslintignore +0 -7
  6. package/.eslintrc.js +0 -11
  7. package/.gitlab-ci.yml +0 -128
  8. package/.mocharc.js +0 -8
  9. package/.nvmrc +0 -1
  10. package/.nycrc +0 -15
  11. package/Dockerfile +0 -17
  12. package/cleanup-docker.sh +0 -4
  13. package/commitlint.config.js +0 -1
  14. package/database/index.ts +0 -76
  15. package/database/migrations/001.do.init.sql +0 -53
  16. package/database/migrations/002.do.add-aggregated-sites.sql +0 -16
  17. package/database/migrations/003.do.add-generated-period-cols.sql +0 -7
  18. package/database/migrations/index.ts +0 -36
  19. package/database/seed/common.ts +0 -7
  20. package/database/seed/index.ts +0 -60
  21. package/database/seed/local/index.ts +0 -28
  22. package/database/seed/production/index.ts +0 -3
  23. package/database/seed/staging/index.ts +0 -5
  24. package/dev.ts +0 -3
  25. package/dist/aggregated-nodes/model/index.js +0 -11
  26. package/docker-compose.yml +0 -42
  27. package/envs/.master.env +0 -7
  28. package/envs/.staging.env +0 -7
  29. package/index.js +0 -3
  30. package/package.serverless.json +0 -21
  31. package/run-docker.sh +0 -14
  32. package/run-test.sh +0 -5
  33. package/scripts/run-lambda.ts +0 -10
  34. package/scripts/run-migrations.ts +0 -18
  35. package/scripts/run-resetdb.ts +0 -18
  36. package/scripts/run-seed.ts +0 -18
  37. package/serverless.yml +0 -101
  38. package/src/aggregated-nodes/model/index.ts +0 -37
  39. package/src/aggregated-nodes/routes/pg-get-filters.ts +0 -54
  40. package/src/aggregated-nodes/routes/pg-get.ts +0 -61
  41. package/src/aggregated-nodes/routes.spec.ts +0 -274
  42. package/src/aggregated-nodes/routes.ts +0 -56
  43. package/src/aggregated-nodes/services/pg-get-filters.ts +0 -62
  44. package/src/aggregated-nodes/services/pg-get.ts +0 -77
  45. package/src/app.spec.ts +0 -34
  46. package/src/app.ts +0 -59
  47. package/src/config.ts +0 -21
  48. package/src/cors.spec.ts +0 -32
  49. package/src/cors.ts +0 -7
  50. package/src/errors.spec.ts +0 -114
  51. package/src/errors.ts +0 -121
  52. package/src/index.spec.ts +0 -94
  53. package/src/index.ts +0 -14
  54. package/src/lambdas/sentry.ts +0 -12
  55. package/src/lambdas/update-aggregated-nodes/handler.spec.ts +0 -77
  56. package/src/lambdas/update-aggregated-nodes/handler.ts +0 -129
  57. package/src/logger.spec.ts +0 -20
  58. package/src/logger.ts +0 -45
  59. package/src/maintenance.spec.ts +0 -76
  60. package/src/maintenance.ts +0 -19
  61. package/src/models.ts +0 -1
  62. package/src/routes.ts +0 -8
  63. package/src/settings/model/index.ts +0 -21
  64. package/src/settings/routes/get.spec.ts +0 -33
  65. package/src/settings/routes/get.ts +0 -3
  66. package/src/settings/routes/update.spec.ts +0 -33
  67. package/src/settings/routes/update.ts +0 -5
  68. package/src/settings/routes.spec.ts +0 -75
  69. package/src/settings/routes.ts +0 -21
  70. package/src/settings/services/get.spec.ts +0 -62
  71. package/src/settings/services/get.ts +0 -18
  72. package/src/settings/services/update.spec.ts +0 -118
  73. package/src/settings/services/update.ts +0 -47
  74. package/src/slack.spec.ts +0 -42
  75. package/src/slack.ts +0 -17
  76. package/src/swagger/routes.ts +0 -57
  77. package/src/types/async-express-errors/index.d.ts +0 -1
  78. package/src/types/express/index.d.ts +0 -10
  79. package/src/utils/endpoint-wrapper.spec.ts +0 -80
  80. package/src/utils/endpoint-wrapper.ts +0 -16
  81. package/src/utils/middleware.spec.ts +0 -154
  82. package/src/utils/middleware.ts +0 -33
  83. package/test/Dockerfile +0 -13
  84. package/test/docker-compose.yml +0 -40
  85. package/test/fixtures/aggregated-nodes/get.ts +0 -196
  86. package/test/fixtures/update-aggregated-nodes/abyssinianKaleSeedWhole-cycle_pivoted.csv +0 -5
  87. package/test/fixtures/update-aggregated-nodes/abyssinianKaleSeedWhole-cycle_pivoted.csv.cycle.json +0 -458
  88. package/test/fixtures/update-aggregated-nodes/abyssinianKaleSeedWhole-cycle_pivoted.csv.site.json +0 -182
  89. package/test/fixtures/update-aggregated-nodes/abyssinianKaleSeedWhole-impactassessment_pivoted.csv +0 -3
  90. package/test/fixtures/update-aggregated-nodes/abyssinianKaleSeedWhole-impactassessment_pivoted.csv.impactAssessment.json +0 -988
  91. package/test/fixtures/update-aggregated-nodes/abyssinianKaleStraw-impactassessment_pivoted.csv +0 -3
  92. package/test/fixtures/update-aggregated-nodes/cycle-missing-impactassessment_pivoted.csv +0 -3
  93. package/test/fixtures/update-aggregated-nodes/tomatoFruit-cycle_pivoted.csv +0 -5
  94. package/test/fixtures/update-aggregated-nodes/tomatoFruit-cycle_pivoted.csv.cycle.json +0 -584
  95. package/test/fixtures/update-aggregated-nodes/tomatoFruit-cycle_pivoted.csv.site.json +0 -212
  96. package/test/fixtures/update-aggregated-nodes/tomatoFruit-impactassessment_pivoted.csv +0 -3
  97. package/test/fixtures/update-aggregated-nodes/tomatoFruit-impactassessment_pivoted.csv.impactAssessment.json +0 -1002
  98. package/test/prepare.ts +0 -13
  99. package/test/utils.ts +0 -32
  100. package/tsconfig.build.json +0 -13
  101. package/tsconfig.dist.json +0 -14
  102. package/tsconfig.json +0 -42
  103. package/tsconfig.lambdas.json +0 -13
package/envs/.staging.env DELETED
@@ -1,7 +0,0 @@
1
- export ENVIRONMENT='staging'
2
- export STAGE='staging'
3
- export PGHOST=$PG_HOST_STAGING
4
- export PGPASSWORD=$PG_PASSWORD_STAGING
5
- export PGDATABASE=$PG_DATABASE
6
- export PGPORT=$PG_PORT
7
- export PGUSER=$PG_USER
package/index.js DELETED
@@ -1,3 +0,0 @@
1
- require('dotenv').config();
2
-
3
- require('./build/src').run();
@@ -1,21 +0,0 @@
1
- {
2
- "name": "@hestia-earth/data-api-serverless",
3
- "dependencies": {
4
- "@hestia-earth/schema": "*",
5
- "@hestia-earth/pipeline-utils": "*",
6
- "@sentry/serverless": "*",
7
- "csvtojson": "*",
8
- "debug": "*",
9
- "exit-hook": "*",
10
- "lodash.chunk": "*",
11
- "lodash.uniqby": "*",
12
- "map-obj": "*",
13
- "pg": "*",
14
- "winston": "*"
15
- },
16
- "devDependencies": {
17
- "serverless": "^3.32.2",
18
- "serverless-deployment-bucket": "^1.6.0",
19
- "serverless-offline": "^12.0.4"
20
- }
21
- }
package/run-docker.sh DELETED
@@ -1,14 +0,0 @@
1
- #!/bin/sh
2
-
3
- docker build --progress=plain \
4
- -t hestia-data-api:latest \
5
- .
6
-
7
- docker run --rm \
8
- --name hestia-data-api \
9
- --env-file .env \
10
- --env PORT=80 \
11
- -v ${PWD}/scripts:/app/scripts \
12
- -v ${PWD}/src:/app/src \
13
- -p 3001:80 \
14
- hestia-data-api:latest npm run dev
package/run-test.sh DELETED
@@ -1,5 +0,0 @@
1
- #!/bin/sh
2
-
3
- docker-compose -f test/docker-compose.yml build
4
- docker-compose -f test/docker-compose.yml run test
5
- docker-compose -f test/docker-compose.yml down
@@ -1,10 +0,0 @@
1
- /* eslint-disable no-console */
2
- import * as dotenv from 'dotenv';
3
- dotenv.config();
4
-
5
- import { updateAggregatedNodes } from '../src/lambdas/update-aggregated-nodes/handler';
6
-
7
- updateAggregatedNodes().then(() => process.exit(0)).catch(err => {
8
- console.error(err);
9
- process.exit(1);
10
- });
@@ -1,18 +0,0 @@
1
- /* eslint-disable no-console */
2
- import * as dotenv from 'dotenv';
3
- dotenv.config();
4
-
5
- import { runMigrations } from '../database/migrations';
6
-
7
- void (async function () {
8
- const { gracefulExit } = await import('exit-hook');
9
-
10
- try {
11
- await runMigrations();
12
- gracefulExit(0);
13
- }
14
- catch (error) {
15
- console.error(error);
16
- gracefulExit(1);
17
- }
18
- })();
@@ -1,18 +0,0 @@
1
- /* eslint-disable no-console */
2
- import * as dotenv from 'dotenv';
3
- dotenv.config();
4
-
5
- import { resetDb } from '../test/utils';
6
-
7
- void (async function () {
8
- const { gracefulExit } = await import('exit-hook');
9
-
10
- try {
11
- await resetDb();
12
- gracefulExit(0);
13
- }
14
- catch (error) {
15
- console.error(error);
16
- gracefulExit(1);
17
- }
18
- })();
@@ -1,18 +0,0 @@
1
- /* eslint-disable no-console */
2
- import * as dotenv from 'dotenv';
3
- dotenv.config();
4
-
5
- import { runSeed } from '../database/seed';
6
-
7
- void (async function () {
8
- const { gracefulExit } = await import('exit-hook');
9
-
10
- try {
11
- await runSeed();
12
- gracefulExit(0);
13
- }
14
- catch (error) {
15
- console.error(error);
16
- gracefulExit(1);
17
- }
18
- })();
package/serverless.yml DELETED
@@ -1,101 +0,0 @@
1
- frameworkVersion: '3'
2
-
3
- service: hestia-data-api
4
-
5
- plugins:
6
- - serverless-deployment-bucket
7
- - serverless-offline
8
-
9
- package:
10
- exclude:
11
- - node_modules/@types/**
12
- # cannot be removed as used in migrations
13
- # - node_modules/typescript/**
14
- - node_modules/**/*.map
15
- - node_modules/**/*.d.ts
16
- - node_modules/**/coverage/**
17
- - node_modules/**/tests/**
18
- - node_modules/**/test/**
19
- - .nyc_output/**
20
- - coverage/**
21
- - data/**
22
- - docs/**
23
- - envs/**
24
- - samples/**
25
- - scripts/**
26
- - test/**
27
- - tmp/**
28
- - tsconfig*
29
- - "*.yml"
30
- - "*.md"
31
- - "*.sh"
32
- - ".dockerignore"
33
- - "Dockerfile"
34
- - "gulpfile.js"
35
-
36
- custom:
37
- serverless-offline:
38
- httpPort: 3002
39
- stage: ${env:STAGE, self:provider.stage}
40
- securityGroup:
41
- staging: sg-0800627978a40527b
42
- prod: sg-049204c3b58a8bd08
43
- subnetId1:
44
- # private 1a
45
- staging: subnet-04ad6e355249c757d
46
- prod: subnet-00c4a891bce6f48e0
47
- subnetId2:
48
- # private 1b
49
- staging: subnet-01260544aaa3c6810
50
- prod: subnet-02365f46c569f5e1a
51
- debugging:
52
- staging: true
53
- prod: false
54
- logLevel:
55
- staging: DEBUG
56
- prod: INFO
57
- bucket: hestia-data-${self:custom.stage}
58
-
59
- provider:
60
- name: aws
61
- runtime: nodejs18.x
62
- region: us-east-1
63
- stage: staging
64
- deploymentBucket:
65
- name: hestia-serverless-${self:custom.stage}
66
- memorySize: 512
67
- timeout: 600
68
- environment:
69
- SERVICE_NAME: ${self:service}
70
- STAGE: ${self:custom.stage}
71
- DEBUG: ${self:custom.debugging.${self:custom.stage}}
72
- LOG_LEVEL: ${self:custom.logLevel.${self:custom.stage}}
73
- SENTRY_DSN: https://00ed710e2b664894a3ff3124bfff24cf@o441427.ingest.sentry.io/4505186792767488
74
- BUCKET: ${self:custom.bucket}
75
- PGHOST: ${env:PGHOST}
76
- PGDATABASE: ${env:PGDATABASE}
77
- PGPORT: ${env:PGPORT}
78
- PGUSER: ${env:PGUSER}
79
- PGPASSWORD: ${env:PGPASSWORD}
80
- iamRoleStatements:
81
- - Effect: Allow
82
- Action:
83
- - s3:GetObject
84
- - s3:GetObjectAcl
85
- - s3:ListObjects
86
- - s3:ListBucket
87
- Resource:
88
- - "arn:aws:s3:::${self:custom.bucket}"
89
- - "arn:aws:s3:::${self:custom.bucket}/*"
90
- vpc:
91
- securityGroupIds:
92
- - ${self:custom.securityGroup.${self:custom.stage}}
93
- subnetIds:
94
- - ${self:custom.subnetId1.${self:custom.stage}}
95
- - ${self:custom.subnetId2.${self:custom.stage}}
96
-
97
- functions:
98
- updateAggregatedNodes:
99
- handler: build/src/lambdas/update-aggregated-nodes/handler.updateAggregatedNodes
100
- events:
101
- - schedule: cron(0 2 * * ? *) # 2:00am every day
@@ -1,37 +0,0 @@
1
- import { ISiteJSONLD } from '@hestia-earth/schema';
2
-
3
- export interface IFilter {
4
- regions?: string[];
5
- periods?: string[];
6
- products?: string[];
7
- defaultMethodClassifications?: string[];
8
- practices?: string[];
9
- minAggregatedQualityScore?: number;
10
- }
11
-
12
- export const validFilterFields = [
13
- 'regions',
14
- 'periods',
15
- 'products',
16
- 'defaultMethodClassifications',
17
- 'practices',
18
- 'minAggregatedQualityScore'
19
- ];
20
-
21
- export interface IFilters {
22
- cycleCount: number;
23
- impactAssessmentCount: number;
24
- products: string[];
25
- periods: string[];
26
- practices: string[];
27
- minAggregatedQualityScore: number[];
28
- regions: string[];
29
- defaultMethodClassifications: string[];
30
- }
31
-
32
- // TODO: update with pivoted types when available
33
- export interface AggregatedNodeRow {
34
- cycle: any; // pivoted cycle
35
- region: ISiteJSONLD['country'];
36
- impactAssessments: [any]; // pivoted impact assessments
37
- }
@@ -1,54 +0,0 @@
1
- import { Request } from 'express';
2
-
3
- import { applyFilters } from '../services/pg-get-filters';
4
-
5
- /**
6
- * @swagger
7
- *
8
- * paths:
9
- * /aggregated-nodes/pg/filters:
10
- * get:
11
- * summary: "Get the additional filters available for a filter selection and node counts (uses PG only)"
12
- * parameters:
13
- * - in: query
14
- * name: filter
15
- * schema:
16
- * type: string
17
- * examples:
18
- * example1:
19
- * summary: Barley in Australia and India between 2010 and 2019.
20
- * value: "regions=GADM-AUS|GADM-IND;\
21
- * products=barleyGrainWhole|barleyStraw;\
22
- * periods=2010-2019"
23
- * example2:
24
- * summary: Wheat and Maize in France, United Kingdom and Worldwide between 2000 and 2019.
25
- * value: "regions=region-world|GADM-GBR|GADM-FRA;\
26
- * products=wheatGrain|maizeGrain;\
27
- * periods=2000-2009|2010-2019"
28
- * description: Set of filters
29
- * - in: query
30
- * name: query
31
- * schema:
32
- * type: string
33
- * example: Wheat
34
- * description: Free search text
35
- * responses:
36
- * 200:
37
- * content:
38
- * application/json:
39
- * schema:
40
- * type: object
41
- * 400:
42
- * $ref: '#/components/responses/BadRequestError'
43
- * 404:
44
- * $ref: '#/components/responses/NotFoundError'
45
- * 500:
46
- * $ref: '#/components/responses/UnexpectedError'
47
- * 503:
48
- * $ref: '#/components/responses/ServiceUnavailable'
49
- */
50
-
51
- export const getFilters = ({ query: qs, filter }: Request) => {
52
- const query = qs.query as string;
53
- return applyFilters({ filter, query });
54
- };
@@ -1,61 +0,0 @@
1
- /* eslint-disable max-len */
2
- import { Request } from 'express';
3
-
4
- import { applyFilter } from '../services/pg-get';
5
-
6
- /**
7
- * @swagger
8
- *
9
- * paths:
10
- * /aggregated-nodes/pg:
11
- * get:
12
- * summary: "Get the aggregated nodes corresponding to a set of filters and search query (uses PG only)"
13
- * parameters:
14
- * - in: query
15
- * name: filter
16
- * schema:
17
- * type: string
18
- * examples:
19
- * example1:
20
- * summary: Barley in Australia and India between 2010 and 2019.
21
- * value: "regions=GADM-AUS|GADM-IND;\
22
- * products=barleyGrainWhole|barleyStraw;\
23
- * periods=2010-2019"
24
- * example2:
25
- * summary: Wheat and Maize in France, United Kingdom and Worldwide between 2000 and 2019.
26
- * value: "regions=region-world|GADM-GBR|GADM-FRA;\
27
- * products=wheatGrain|maizeGrain;\
28
- * periods=2000-2009|2010-2019"
29
- * description: Set of filters
30
- * - in: query
31
- * name: page
32
- * schema:
33
- * type: integer
34
- * example: 1
35
- * - in: query
36
- * name: query
37
- * schema:
38
- * type: string
39
- * example: Wheat
40
- * description: Free search text
41
- * responses:
42
- * 200:
43
- * content:
44
- * application/json:
45
- * schema:
46
- * type: object
47
- * 400:
48
- * $ref: '#/components/responses/BadRequestError'
49
- * 404:
50
- * $ref: '#/components/responses/NotFoundError'
51
- * 500:
52
- * $ref: '#/components/responses/UnexpectedError'
53
- * 503:
54
- * $ref: '#/components/responses/ServiceUnavailable'
55
- */
56
-
57
- export const get = ({ query: qs, filter }: Request) => {
58
- const page = Number(qs.page) || 1;
59
- const query = qs.query as string;
60
- return applyFilter({ page, filter, query });
61
- };
@@ -1,274 +0,0 @@
1
- import { expect } from 'chai';
2
- import * as sinon from 'sinon';
3
- import 'mocha';
4
- import express from 'express';
5
- import supertest from 'supertest';
6
- import bodyParser from 'body-parser';
7
-
8
- import router from './routes';
9
- import { Errors, errorHandler } from '../errors';
10
- import { initDb } from '../../test/utils';
11
- import { seed } from '../../database/seed';
12
-
13
- import * as fixtures from '../../test/fixtures/aggregated-nodes/get';
14
-
15
- let stubs: sinon.SinonStub[] = [];
16
-
17
- const app = express();
18
-
19
- const getFixtureNode = (type: 'site' | 'cycle' | 'impactAssessment', id: string) =>
20
- fixtures[
21
- { cycle: 'aggregatedCycles', site: 'aggregatedSites', impactAssessment: 'aggregatedImpactAssessments' }[type]
22
- ].find((node) => node.jsonld_pivoted['@id'] === id).jsonld_pivoted;
23
-
24
- app.use(bodyParser.json());
25
- app.use(router());
26
- app.use(errorHandler);
27
-
28
- describe('routes', () => {
29
- beforeEach(() => {
30
- stubs = [];
31
- });
32
-
33
- afterEach(() => {
34
- stubs.forEach((stub) => stub.restore());
35
- });
36
-
37
- describe('aggregated-nodes', () => {
38
- beforeEach(async () => {
39
- await initDb();
40
- await seed(fixtures);
41
- });
42
-
43
- describe('GET /pg', () => {
44
- it('when invalid filter passed returns invalid param error', async () => {
45
- const result = await supertest(app)
46
- .get('/pg')
47
- .query({ filter: 'invalidfilter' })
48
- .set('Accept', 'application/json');
49
-
50
- expect(result.body.message).to.equal(Errors.InvalidQueryParam);
51
- });
52
-
53
- it('when neither filter nor query passed returns missing param error', async () => {
54
- const result = await supertest(app).get('/pg').query({}).set('Accept', 'application/json');
55
-
56
- expect(result.body.message).to.equal(Errors.MissingQueryParam);
57
- });
58
-
59
- it('can filter by regions', async () => {
60
- const expected = [
61
- {
62
- cycle: getFixtureNode('cycle', '1'),
63
- region: getFixtureNode('site', '1').country,
64
- impactAssessments: [getFixtureNode('impactAssessment', '1'), getFixtureNode('impactAssessment', '2')]
65
- },
66
- {
67
- cycle: getFixtureNode('cycle', '2'),
68
- region: getFixtureNode('site', '1').country,
69
- impactAssessments: [getFixtureNode('impactAssessment', '3')]
70
- },
71
- {
72
- cycle: getFixtureNode('cycle', '3'),
73
- region: getFixtureNode('site', '2').country,
74
- impactAssessments: [getFixtureNode('impactAssessment', '4')]
75
- }
76
- ];
77
-
78
- const filter = 'regions=GADM-POL|GADM-DEU';
79
- const result = await supertest(app).get('/pg').query({ filter }).set('Accept', 'application/json');
80
- expect(result.body.results).to.deep.equal(expected);
81
- });
82
-
83
- it('can filter by practices', async () => {
84
- const expected = [
85
- {
86
- cycle: getFixtureNode('cycle', '1'),
87
- region: getFixtureNode('site', '1').country,
88
- impactAssessments: [getFixtureNode('impactAssessment', '1'), getFixtureNode('impactAssessment', '2')]
89
- },
90
- {
91
- cycle: getFixtureNode('cycle', '2'),
92
- region: getFixtureNode('site', '1').country,
93
- impactAssessments: [getFixtureNode('impactAssessment', '3')]
94
- }
95
- ];
96
- const filter = 'practices=earthingUpByHand|deepRipping';
97
- const result = await supertest(app).get('/pg').query({ filter }).set('Accept', 'application/json');
98
- expect(result.body.results).to.deep.equal(expected);
99
- });
100
-
101
- it('can filter by minimum aggregatedQualityScore', async () => {
102
- const expected = [
103
- {
104
- cycle: getFixtureNode('cycle', '1'),
105
- region: getFixtureNode('site', '1').country,
106
- impactAssessments: [getFixtureNode('impactAssessment', '1'), getFixtureNode('impactAssessment', '2')]
107
- }
108
- ];
109
- const filter = 'minAggregatedQualityScore=3';
110
- const result = await supertest(app).get('/pg').query({ filter }).set('Accept', 'application/json');
111
- expect(result.body.results).to.deep.equal(expected);
112
- });
113
-
114
- it('can filter by defaultMethodClassifications', async () => {
115
- const expected = [
116
- {
117
- cycle: getFixtureNode('cycle', '2'),
118
- region: getFixtureNode('site', '1').country,
119
- impactAssessments: [getFixtureNode('impactAssessment', '3')]
120
- },
121
- {
122
- cycle: getFixtureNode('cycle', '3'),
123
- region: getFixtureNode('site', '2').country,
124
- impactAssessments: [getFixtureNode('impactAssessment', '4')]
125
- }
126
- ];
127
- const filter = 'defaultMethodClassifications=physical measurement|expert opinion';
128
- const result = await supertest(app).get('/pg').query({ filter }).set('Accept', 'application/json');
129
- expect(result.body.results).to.deep.equal(expected);
130
- });
131
-
132
- it('can filter by periods', async () => {
133
- const expected = [
134
- {
135
- cycle: getFixtureNode('cycle', '3'),
136
- region: getFixtureNode('site', '2').country,
137
- impactAssessments: [getFixtureNode('impactAssessment', '4')]
138
- },
139
- {
140
- cycle: getFixtureNode('cycle', '4'),
141
- region: getFixtureNode('site', '3').country,
142
- impactAssessments: []
143
- }
144
- ];
145
- const filter = 'periods=2010-2019|2000-2009';
146
- const result = await supertest(app).get('/pg').query({ filter }).set('Accept', 'application/json');
147
- expect(result.body.results).to.deep.equal(expected);
148
- });
149
-
150
- it('can filter by products', async () => {
151
- const expected = [
152
- {
153
- cycle: getFixtureNode('cycle', '1'),
154
- region: getFixtureNode('site', '1').country,
155
- // impactAssessments have also been filtered
156
- impactAssessments: [getFixtureNode('impactAssessment', '1')]
157
- },
158
- {
159
- cycle: getFixtureNode('cycle', '2'),
160
- region: getFixtureNode('site', '1').country,
161
- impactAssessments: [getFixtureNode('impactAssessment', '3')]
162
- }
163
- ];
164
- const filter = 'products=wheatGrain|fishFingerlings';
165
- const result = await supertest(app).get('/pg').query({ filter }).set('Accept', 'application/json');
166
- expect(result.body.results).to.deep.equal(expected);
167
- });
168
-
169
- it('can combine multiple filters', async () => {
170
- const expected = [
171
- {
172
- cycle: getFixtureNode('cycle', '5'),
173
- region: getFixtureNode('site', '3').country,
174
- // impactAssessments have also been filtered
175
- impactAssessments: []
176
- }
177
- ];
178
- const filter = [
179
- 'regions=GADM-POL|GADM-DEU|GADM-BRA',
180
- 'products=wheatGrain|fishFingerlings|cheese',
181
- 'periods=2010-2019|2020-2029',
182
- 'defaultMethodClassifications=modelled|expert opinion',
183
- 'minAggregatedQualityScore=2',
184
- 'practices=earthingUpByHand|deepRipping|baggingFruit'
185
- ].join(';');
186
- const result = await supertest(app).get('/pg').query({ filter }).set('Accept', 'application/json');
187
- expect(result.body.results).to.deep.equal(expected);
188
- });
189
- });
190
-
191
- describe('GET /pg/filters', () => {
192
- it('when invalid filter passed returns invalid param error', async () => {
193
- const result = await supertest(app)
194
- .get('/pg/filters')
195
- .query({ filter: 'invalidfilter' })
196
- .set('Accept', 'application/json');
197
-
198
- expect(result.body.message).to.equal(Errors.InvalidQueryParam);
199
- });
200
-
201
- describe('returns the filters and node counts available for the current selection', () => {
202
- it('returns subset of filters corresponding to selected nodes', async () => {
203
- const expected = {
204
- cycleCount: 1,
205
- impactAssessmentCount: 0,
206
- products: ['apples', 'cheese'],
207
- periods: ['2020-2029'],
208
- practices: ['baggingFruit'],
209
- minAggregatedQualityScore: [2],
210
- regions: ['GADM-BRA'],
211
- defaultMethodClassifications: ['modelled']
212
- };
213
- const filter = [
214
- 'regions=GADM-POL|GADM-DEU|GADM-BRA',
215
- 'products=wheatGrain|fishFingerlings|cheese',
216
- 'periods=2010-2019|2020-2029',
217
- 'defaultMethodClassifications=modelled|expert opinion',
218
- 'minAggregatedQualityScore=2',
219
- 'practices=earthingUpByHand|deepRipping|baggingFruit'
220
- ].join(';');
221
- const result = await supertest(app).get('/pg/filters').query({ filter }).set('Accept', 'application/json');
222
- expect(result.body).to.deep.equal(expected);
223
- });
224
-
225
- it('returns all filters when there is nothing currently selected', async () => {
226
- const expected = {
227
- cycleCount: 9,
228
- impactAssessmentCount: 4,
229
- products: ['apples', 'barley', 'cheese', 'fishFingerlings', 'wheatGrain'],
230
- periods: ['1980-1989', '1990-1999', '2000-2009', '2010-2019', '2020-2029'],
231
- practices: ['baggingFruit', 'deepRipping', 'earthingUpByHand'],
232
- minAggregatedQualityScore: [1, 2, 3],
233
- regions: ['GADM-BRA', 'GADM-DEU', 'GADM-POL'],
234
- defaultMethodClassifications: ['expert opinion', 'modelled', 'physical measurement', 'unsourced assumption']
235
- };
236
- const result = await supertest(app).get('/pg/filters').query({}).set('Accept', 'application/json');
237
- expect(result.body).to.deep.equal(expected);
238
- });
239
-
240
- it('does not exclude nodes with missing practices key', async () => {
241
- const expected = {
242
- cycleCount: 1,
243
- impactAssessmentCount: 0,
244
- products: ['apples', 'cheese'],
245
- periods: ['1980-1989'],
246
- practices: [],
247
- minAggregatedQualityScore: [2],
248
- regions: ['GADM-BRA'],
249
- defaultMethodClassifications: ['modelled']
250
- };
251
- const filter = ['regions=GADM-BRA', 'periods=1980-1989'].join(';');
252
- const result = await supertest(app).get('/pg/filters').query({ filter }).set('Accept', 'application/json');
253
- expect(result.body).to.deep.equal(expected);
254
- });
255
-
256
- it('returns empty arrays when no filters available', async () => {
257
- const expected = {
258
- cycleCount: 0,
259
- impactAssessmentCount: 0,
260
- products: [],
261
- periods: [],
262
- practices: [],
263
- minAggregatedQualityScore: [],
264
- regions: [],
265
- defaultMethodClassifications: []
266
- };
267
- const filter = ['products=grapes'].join(';');
268
- const result = await supertest(app).get('/pg/filters').query({ filter }).set('Accept', 'application/json');
269
- expect(result.body).to.deep.equal(expected);
270
- });
271
- });
272
- });
273
- });
274
- });