From a92728aa0d18ceee060aa60115edf30a45552a7f Mon Sep 17 00:00:00 2001 From: Gwynn Dandridge-Perry Date: Wed, 19 Apr 2023 08:54:16 -0700 Subject: [PATCH 01/65] feat: add reference_id as a valid field for growers query --- server/infra/database/GrowerAccountRepository.ts | 11 ++++++++++- server/routers/growerAccountsRouter.ts | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/server/infra/database/GrowerAccountRepository.ts b/server/infra/database/GrowerAccountRepository.ts index a58079ca..ef404a49 100644 --- a/server/infra/database/GrowerAccountRepository.ts +++ b/server/infra/database/GrowerAccountRepository.ts @@ -40,6 +40,15 @@ export default class GrowerAccountRepository extends BaseRepository Date: Fri, 21 Apr 2023 18:14:49 -0700 Subject: [PATCH 03/65] feat: add grower_reference_id as a filter field for captures --- server/infra/database/CaptureRepository.ts | 8 ++++++++ server/routers/capturesRouter.ts | 2 ++ 2 files changed, 10 insertions(+) diff --git a/server/infra/database/CaptureRepository.ts b/server/infra/database/CaptureRepository.ts index e0c3e30b..e0b46747 100644 --- a/server/infra/database/CaptureRepository.ts +++ b/server/infra/database/CaptureRepository.ts @@ -90,6 +90,14 @@ export default class CaptureRepository extends BaseRepository { ); delete filterObject.reference_id; } + if (filterObject.grower_reference_id) { + result.where( + `treetracker.grower_account.reference_id`, + '=', + filterObject.grower_reference_id, + ); + delete filterObject.grower_reference_id; + } if (filterObject.organization_id) { result.where(`${this.tableName}.planting_organization_id`, 'in', [ diff --git a/server/routers/capturesRouter.ts b/server/routers/capturesRouter.ts index 733ebc61..e7530b84 100644 --- a/server/routers/capturesRouter.ts +++ b/server/routers/capturesRouter.ts @@ -17,6 +17,7 @@ router.get( query, Joi.object().keys({ grower_account_id: Joi.string().uuid(), + grower_reference_id: Joi.number(), organization_id: Joi.array(), limit: Joi.number().integer().min(1).max(20000), offset: Joi.number().integer().min(0), @@ -71,6 +72,7 @@ router.get( query, Joi.object().keys({ grower_account_id: Joi.string().uuid(), + grower_reference_id: Joi.number(), organization_id: Joi.array(), limit: Joi.number().integer().min(1).max(20000), offset: Joi.number().integer().min(0), From 3a8b1ccdb9fc6d03e0b4126e022d77a6679286ef Mon Sep 17 00:00:00 2001 From: Gwynn Dandridge-Perry Date: Sat, 22 Apr 2023 14:48:09 -0700 Subject: [PATCH 04/65] feat: add grower_reference_id as a filter field for verify --- server/infra/database/CaptureRepository.ts | 1 + server/infra/database/RawCaptureRepository.ts | 21 +++++++++++++++++++ server/routers/rawCapturesRouter.ts | 2 ++ 3 files changed, 24 insertions(+) diff --git a/server/infra/database/CaptureRepository.ts b/server/infra/database/CaptureRepository.ts index e0b46747..0ebcc028 100644 --- a/server/infra/database/CaptureRepository.ts +++ b/server/infra/database/CaptureRepository.ts @@ -90,6 +90,7 @@ export default class CaptureRepository extends BaseRepository { ); delete filterObject.reference_id; } + if (filterObject.grower_reference_id) { result.where( `treetracker.grower_account.reference_id`, diff --git a/server/infra/database/RawCaptureRepository.ts b/server/infra/database/RawCaptureRepository.ts index ff91c707..eb7b9ba6 100644 --- a/server/infra/database/RawCaptureRepository.ts +++ b/server/infra/database/RawCaptureRepository.ts @@ -100,6 +100,15 @@ export default class RawCaptureRepository extends BaseRepository { delete filterObject.reference_id; } + if (filterObject.grower_reference_id) { + result.where( + `treetracker.grower_account.reference_id`, + '=', + filterObject.grower_reference_id, + ); + delete filterObject.grower_reference_id; + } + if (filterObject.organization_id) { result.where(`field_data.session.organization_id`, 'in', [ ...filterObject.organization_id, @@ -152,6 +161,12 @@ export default class RawCaptureRepository extends BaseRepository { '=', 'field_data.wallet_registration.id', ) + .leftJoin( + 'treetracker.grower_account', + 'field_data.wallet_registration.grower_account_id', + '=', + 'treetracker.grower_account.id', + ) .leftJoin( 'field_data.device_configuration', 'field_data.session.device_configuration_id', @@ -202,6 +217,12 @@ export default class RawCaptureRepository extends BaseRepository { '=', 'field_data.wallet_registration.id', ) + .leftJoin( + 'treetracker.grower_account', + 'field_data.wallet_registration.grower_account_id', + '=', + 'treetracker.grower_account.id', + ) .leftJoin( 'field_data.device_configuration', 'field_data.session.device_configuration_id', diff --git a/server/routers/rawCapturesRouter.ts b/server/routers/rawCapturesRouter.ts index 5ee74cd3..58e96d08 100644 --- a/server/routers/rawCapturesRouter.ts +++ b/server/routers/rawCapturesRouter.ts @@ -21,6 +21,7 @@ router.get( status: Joi.string().allow('unprocessed', 'approved', 'rejected'), bulk_pack_file_name: Joi.string(), grower_account_id: Joi.string().uuid(), + grower_reference_id: Joi.number(), organization_id: Joi.array(), startDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), endDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), @@ -76,6 +77,7 @@ router.get( status: Joi.string().allow('unprocessed', 'approved', 'rejected'), bulk_pack_file_name: Joi.string(), grower_account_id: Joi.string().uuid(), + grower_reference_id: Joi.number(), organization_id: Joi.array(), startDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), endDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), From f6c33bf64daf13b7b537927efde87fade867b298 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 25 Apr 2023 07:58:46 +0000 Subject: [PATCH 05/65] chore(release): 1.66.0 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27c51418..fb07c760 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# [1.66.0](https://github.com/Greenstand/treetracker-query-api/compare/v1.65.0...v1.66.0) (2023-04-25) + +### Features + +- make results of captures query distinct to avoid duplicates ([7d99679](https://github.com/Greenstand/treetracker-query-api/commit/7d996798bfbf8cfd66678e12c4061c84709883f3)) + # [1.65.0](https://github.com/Greenstand/treetracker-query-api/compare/v1.64.0...v1.65.0) (2023-03-29) ### Bug Fixes diff --git a/package.json b/package.json index a06f35f5..0f8f78de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.65.0", + "version": "1.66.0", "private": false, "keywords": [ "ecology" From 68dc67489b8872f74c8ebc44b2202172bb136df5 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 25 Apr 2023 08:02:12 +0000 Subject: [PATCH 06/65] chore(release): 1.67.0 [skip ci] --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb07c760..1c0df4d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# [1.67.0](https://github.com/Greenstand/treetracker-query-api/compare/v1.66.0...v1.67.0) (2023-04-25) + +### Features + +- add grower_reference_id as a filter field for captures ([b6bea8c](https://github.com/Greenstand/treetracker-query-api/commit/b6bea8cd210a6869b312d95b119c2bbed65cdee8)) +- add grower_reference_id as a filter field for verify ([3a8b1cc](https://github.com/Greenstand/treetracker-query-api/commit/3a8b1ccdb9fc6d03e0b4126e022d77a6679286ef)) +- add reference_id as a valid field for growers query ([a92728a](https://github.com/Greenstand/treetracker-query-api/commit/a92728aa0d18ceee060aa60115edf30a45552a7f)) + # [1.66.0](https://github.com/Greenstand/treetracker-query-api/compare/v1.65.0...v1.66.0) (2023-04-25) ### Features diff --git a/package.json b/package.json index 0f8f78de..b3967aa0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.66.0", + "version": "1.67.0", "private": false, "keywords": [ "ecology" From fac9485658f4b83af814d701ef32dd8ae4958dbd Mon Sep 17 00:00:00 2001 From: root Date: Thu, 4 May 2023 09:54:57 +0000 Subject: [PATCH 07/65] fix: uuid capital problem --- server/infra/database/TokensRepository.ts | 2 +- server/infra/database/TreeRepository.ts | 6 +++--- server/infra/database/TreeRepositoryV2.ts | 4 ++-- server/infra/database/WalletsRepository.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/server/infra/database/TokensRepository.ts b/server/infra/database/TokensRepository.ts index 89fe7d59..3330fd35 100644 --- a/server/infra/database/TokensRepository.ts +++ b/server/infra/database/TokensRepository.ts @@ -20,7 +20,7 @@ export default class TokensRepository extends BaseRepository { public.tree_species.name as tree_species_name from wallet.token left join public.trees on - wallet.token.capture_id::text = public.trees.uuid::text + wallet.token.capture_id::text = lower(public.trees.uuid::text) left join public.tree_species on public.trees.species_id = public.tree_species.id where wallet.token.id = '${tokenId}' diff --git a/server/infra/database/TreeRepository.ts b/server/infra/database/TreeRepository.ts index b4f5fcb3..8f9201e4 100644 --- a/server/infra/database/TreeRepository.ts +++ b/server/infra/database/TreeRepository.ts @@ -36,7 +36,7 @@ export default class TreeRepository extends BaseRepository { on ST_WITHIN(trees.estimated_geometric_location, region.geom) and region.type_id in (select id from region_type where type = 'country') left JOIN wallet.token - on wallet.token.capture_id::text = trees.uuid::text + on wallet.token.capture_id::text = lower(trees.uuid::text) left JOIN wallet.wallet on wallet.token.wallet_id = wallet.wallet.id `), @@ -234,7 +234,7 @@ export default class TreeRepository extends BaseRepository { SELECT COUNT(*) FROM trees - LEFT JOIN wallet.token ON token.capture_id::text = trees.uuid + LEFT JOIN wallet.token ON token.capture_id::text = lower(trees.uuid) WHERE wallet.token.wallet_id = '${wallet_id}' `; const total = await this.session.getDB().raw(totalSql); @@ -245,7 +245,7 @@ export default class TreeRepository extends BaseRepository { SELECT trees.* FROM trees - LEFT JOIN wallet.token ON token.capture_id::text = trees.uuid + LEFT JOIN wallet.token ON token.capture_id::text = lower(trees.uuid) WHERE wallet.token.wallet_id = '${wallet_id}' LIMIT ${limit} OFFSET ${offset} diff --git a/server/infra/database/TreeRepositoryV2.ts b/server/infra/database/TreeRepositoryV2.ts index 5021c2ce..e6840039 100644 --- a/server/infra/database/TreeRepositoryV2.ts +++ b/server/infra/database/TreeRepositoryV2.ts @@ -199,7 +199,7 @@ export default class TreeRepositoryV2 extends BaseRepository { SELECT COUNT(*) FROM trees - LEFT JOIN wallet.token ON token.capture_id::text = trees.uuid + LEFT JOIN wallet.token ON token.capture_id::text = lower(trees.uuid) WHERE wallet.token.wallet_id = '${wallet_id}' `; const total = await this.session.getDB().raw(totalSql); @@ -210,7 +210,7 @@ export default class TreeRepositoryV2 extends BaseRepository { SELECT trees.* FROM trees - LEFT JOIN wallet.token ON token.capture_id::text = trees.uuid + LEFT JOIN wallet.token ON token.capture_id::text = lower(trees.uuid) WHERE wallet.token.wallet_id = '${wallet_id}' LIMIT ${limit} OFFSET ${offset} diff --git a/server/infra/database/WalletsRepository.ts b/server/infra/database/WalletsRepository.ts index 6fd951a3..906db3f7 100644 --- a/server/infra/database/WalletsRepository.ts +++ b/server/infra/database/WalletsRepository.ts @@ -49,7 +49,7 @@ export default class WalletsRepository extends BaseRepository { left join wallet.token on wallet.token.wallet_id = wallet.wallet.id left join public.trees on - wallet.token.capture_id::text = public.trees.uuid::text + wallet.token.capture_id::text = lower(public.trees.uuid::text) left join region as continent on ST_WITHIN(public.trees.estimated_geometric_location, continent.geom) and continent.type_id in (select id from region_type where type = 'continents' ) From d1e064c64a1e8f48f457cb0bb04347e44bfd8ef5 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 4 May 2023 10:00:39 +0000 Subject: [PATCH 08/65] chore(release): 1.67.1 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c0df4d1..124cafef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.67.1](https://github.com/Greenstand/treetracker-query-api/compare/v1.67.0...v1.67.1) (2023-05-04) + +### Bug Fixes + +- uuid capital problem ([fac9485](https://github.com/Greenstand/treetracker-query-api/commit/fac9485658f4b83af814d701ef32dd8ae4958dbd)) + # [1.67.0](https://github.com/Greenstand/treetracker-query-api/compare/v1.66.0...v1.67.0) (2023-04-25) ### Features diff --git a/package.json b/package.json index b3967aa0..aee65e69 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.67.0", + "version": "1.67.1", "private": false, "keywords": [ "ecology" From bb8e730ceea2a09d7a2636605d859e8f053fcb31 Mon Sep 17 00:00:00 2001 From: Dadiorchen Date: Sat, 20 May 2023 16:30:04 +0800 Subject: [PATCH 09/65] fix: remove `v2` and let's the client to decide the version number --- server/models/GrowerAccount.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/models/GrowerAccount.ts b/server/models/GrowerAccount.ts index 242c67f4..9f797b5e 100644 --- a/server/models/GrowerAccount.ts +++ b/server/models/GrowerAccount.ts @@ -51,7 +51,7 @@ function getByName( function getGrowerAccountLinks(planter) { const links = { - featured_trees: `/v2/trees?planter_id=${planter.id}&limit=20&offset=0`, + featured_trees: `/trees?planter_id=${planter.id}&limit=20&offset=0`, associated_organizations: `/organizations?planter_id=${planter.id}&limit=20&offset=0`, species: `/species?planter_id=${planter.id}&limit=20&offset=0`, }; From c1b13cf06656fbf08a1254fc529fd7c145227acb Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 20 May 2023 08:31:13 +0000 Subject: [PATCH 10/65] chore(release): 1.67.2 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 124cafef..c66b3394 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.67.2](https://github.com/Greenstand/treetracker-query-api/compare/v1.67.1...v1.67.2) (2023-05-20) + +### Bug Fixes + +- remove `v2` and let's the client to decide the version number ([bb8e730](https://github.com/Greenstand/treetracker-query-api/commit/bb8e730ceea2a09d7a2636605d859e8f053fcb31)) + ## [1.67.1](https://github.com/Greenstand/treetracker-query-api/compare/v1.67.0...v1.67.1) (2023-05-04) ### Bug Fixes diff --git a/package.json b/package.json index aee65e69..bede9279 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.67.1", + "version": "1.67.2", "private": false, "keywords": [ "ecology" From e7b4cab29273beea9e7ed1f2dd74372f66e4c67e Mon Sep 17 00:00:00 2001 From: deanchen Date: Fri, 26 May 2023 17:29:05 +0800 Subject: [PATCH 11/65] fix: wrong tree count --- server/infra/database/TreeRepository.ts | 9 ++++++++- server/routers/treesRouter.ts | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/server/infra/database/TreeRepository.ts b/server/infra/database/TreeRepository.ts index 8f9201e4..7f3c0204 100644 --- a/server/infra/database/TreeRepository.ts +++ b/server/infra/database/TreeRepository.ts @@ -68,7 +68,7 @@ export default class TreeRepository extends BaseRepository { planter.organization_id in ( SELECT entity_id from getEntityRelationshipChildren(${organization_id})) OR trees.planting_organization_id = ${organization_id} - ) + ) and trees.active = true `; const total = await this.session.getDB().raw(totalSql); return parseInt(total.rows[0].count.toString()); @@ -97,6 +97,7 @@ export default class TreeRepository extends BaseRepository { OR trees.planting_organization_id = ${organization_id} ) + and trees.active = true LIMIT ${limit} OFFSET ${offset} `; @@ -122,6 +123,7 @@ export default class TreeRepository extends BaseRepository { FROM trees WHERE time_created >= '${startDateISO}'::timestamp AND time_created < '${endDateISO}'::timestamp + and trees.active = true `; const total = await this.session.getDB().raw(totalSql); return parseInt(total.rows[0].count.toString()); @@ -146,6 +148,7 @@ export default class TreeRepository extends BaseRepository { and region.type_id in (select id from region_type where type = 'country') WHERE time_created >= '${startDateISO}'::timestamp AND time_created < '${endDateISO}'::timestamp + and trees.active = true LIMIT ${limit} OFFSET ${offset} `; @@ -167,6 +170,7 @@ export default class TreeRepository extends BaseRepository { on tree_tag.tag_id = tag.id WHERE tag.tag_name in ('${tag}') + and trees.active = true `; const total = await this.session.getDB().raw(totalSql); return parseInt(total.rows[0].count.toString()); @@ -194,6 +198,7 @@ export default class TreeRepository extends BaseRepository { on tree_tag.tag_id = tag.id WHERE tag.tag_name in ('${tag}') + and trees.active = true LIMIT ${limit} OFFSET ${offset} `; @@ -236,6 +241,7 @@ export default class TreeRepository extends BaseRepository { FROM trees LEFT JOIN wallet.token ON token.capture_id::text = lower(trees.uuid) WHERE wallet.token.wallet_id = '${wallet_id}' + and trees.active = true `; const total = await this.session.getDB().raw(totalSql); return parseInt(total.rows[0].count.toString()); @@ -247,6 +253,7 @@ export default class TreeRepository extends BaseRepository { FROM trees LEFT JOIN wallet.token ON token.capture_id::text = lower(trees.uuid) WHERE wallet.token.wallet_id = '${wallet_id}' + and trees.active = true LIMIT ${limit} OFFSET ${offset} `; diff --git a/server/routers/treesRouter.ts b/server/routers/treesRouter.ts index 69b59392..9a082ab7 100644 --- a/server/routers/treesRouter.ts +++ b/server/routers/treesRouter.ts @@ -14,6 +14,7 @@ type Filter = Partial<{ date_range: { startDate: string; endDate: string }; tag: string; wallet_id: string; + active: true; }>; router.get( @@ -72,7 +73,7 @@ router.get( wallet_id, } = req.query; const repo = new TreeRepository(new Session()); - const filter: Filter = {}; + const filter: Filter = { active: true }; const options: FilterOptions = { limit, offset, From 14dae9219a6baf4504e596969cc9615583822bb9 Mon Sep 17 00:00:00 2001 From: deanchen Date: Fri, 26 May 2023 17:37:59 +0800 Subject: [PATCH 12/65] fix: wrong planter count --- server/infra/database/PlanterRepository.ts | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/server/infra/database/PlanterRepository.ts b/server/infra/database/PlanterRepository.ts index 43464e13..f5b62cff 100644 --- a/server/infra/database/PlanterRepository.ts +++ b/server/infra/database/PlanterRepository.ts @@ -53,13 +53,10 @@ export default class PlanterRepository extends BaseRepository { LEFT JOIN planter_registrations ON planter.id = planter_registrations.planter_id LEFT JOIN webmap.planter_location l ON l.id = planter.id - WHERE planter.organization_id = ${organization_id} + WHERE planter.organization_id in (select entity_id from getEntityRelationshipChildren(${organization_id})) ${ options.orderBy - ? `order by ${ - options.orderBy.column - } ${ - options.orderBy.direction}` + ? `order by ${options.orderBy.column} ${options.orderBy.direction}` : '' } LIMIT ${limit} @@ -88,7 +85,7 @@ export default class PlanterRepository extends BaseRepository { SELECT COUNT(*) FROM planter - WHERE planter.organization_id = ${organization_id} + WHERE planter.organization_id in (select entity_id from getEntityRelationshipChildren(${organization_id})) `; const total = await this.session.getDB().raw(totalSql); return parseInt(total.rows[0].count.toString()); @@ -107,10 +104,7 @@ export default class PlanterRepository extends BaseRepository { LEFT JOIN webmap.planter_location l ON l.id = planter.id ${ options.orderBy - ? `order by ${ - options.orderBy.column - } ${ - options.orderBy.direction}` + ? `order by ${options.orderBy.column} ${options.orderBy.direction}` : '' } LIMIT ${limit} From 9270968e365d070fce504bccac4086146642456a Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 27 May 2023 01:21:17 +0000 Subject: [PATCH 13/65] chore(release): 1.67.3 [skip ci] --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c66b3394..95197607 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.67.3](https://github.com/Greenstand/treetracker-query-api/compare/v1.67.2...v1.67.3) (2023-05-27) + +### Bug Fixes + +- wrong planter count ([14dae92](https://github.com/Greenstand/treetracker-query-api/commit/14dae9219a6baf4504e596969cc9615583822bb9)) +- wrong tree count ([e7b4cab](https://github.com/Greenstand/treetracker-query-api/commit/e7b4cab29273beea9e7ed1f2dd74372f66e4c67e)) + ## [1.67.2](https://github.com/Greenstand/treetracker-query-api/compare/v1.67.1...v1.67.2) (2023-05-20) ### Bug Fixes diff --git a/package.json b/package.json index bede9279..364e2501 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.67.2", + "version": "1.67.3", "private": false, "keywords": [ "ecology" From fdf55cd8f60b11a672edb876098ae55a50d9a173 Mon Sep 17 00:00:00 2001 From: Dadiorchen Date: Sat, 27 May 2023 15:44:42 +0800 Subject: [PATCH 14/65] Revert "fix: uuid capital problem" --- server/infra/database/TokensRepository.ts | 2 +- server/infra/database/TreeRepository.ts | 6 +++--- server/infra/database/TreeRepositoryV2.ts | 4 ++-- server/infra/database/WalletsRepository.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/server/infra/database/TokensRepository.ts b/server/infra/database/TokensRepository.ts index 3330fd35..89fe7d59 100644 --- a/server/infra/database/TokensRepository.ts +++ b/server/infra/database/TokensRepository.ts @@ -20,7 +20,7 @@ export default class TokensRepository extends BaseRepository { public.tree_species.name as tree_species_name from wallet.token left join public.trees on - wallet.token.capture_id::text = lower(public.trees.uuid::text) + wallet.token.capture_id::text = public.trees.uuid::text left join public.tree_species on public.trees.species_id = public.tree_species.id where wallet.token.id = '${tokenId}' diff --git a/server/infra/database/TreeRepository.ts b/server/infra/database/TreeRepository.ts index 7f3c0204..e7775875 100644 --- a/server/infra/database/TreeRepository.ts +++ b/server/infra/database/TreeRepository.ts @@ -36,7 +36,7 @@ export default class TreeRepository extends BaseRepository { on ST_WITHIN(trees.estimated_geometric_location, region.geom) and region.type_id in (select id from region_type where type = 'country') left JOIN wallet.token - on wallet.token.capture_id::text = lower(trees.uuid::text) + on wallet.token.capture_id::text = trees.uuid::text left JOIN wallet.wallet on wallet.token.wallet_id = wallet.wallet.id `), @@ -239,7 +239,7 @@ export default class TreeRepository extends BaseRepository { SELECT COUNT(*) FROM trees - LEFT JOIN wallet.token ON token.capture_id::text = lower(trees.uuid) + LEFT JOIN wallet.token ON token.capture_id::text = trees.uuid WHERE wallet.token.wallet_id = '${wallet_id}' and trees.active = true `; @@ -251,7 +251,7 @@ export default class TreeRepository extends BaseRepository { SELECT trees.* FROM trees - LEFT JOIN wallet.token ON token.capture_id::text = lower(trees.uuid) + LEFT JOIN wallet.token ON token.capture_id::text = trees.uuid WHERE wallet.token.wallet_id = '${wallet_id}' and trees.active = true LIMIT ${limit} diff --git a/server/infra/database/TreeRepositoryV2.ts b/server/infra/database/TreeRepositoryV2.ts index e6840039..5021c2ce 100644 --- a/server/infra/database/TreeRepositoryV2.ts +++ b/server/infra/database/TreeRepositoryV2.ts @@ -199,7 +199,7 @@ export default class TreeRepositoryV2 extends BaseRepository { SELECT COUNT(*) FROM trees - LEFT JOIN wallet.token ON token.capture_id::text = lower(trees.uuid) + LEFT JOIN wallet.token ON token.capture_id::text = trees.uuid WHERE wallet.token.wallet_id = '${wallet_id}' `; const total = await this.session.getDB().raw(totalSql); @@ -210,7 +210,7 @@ export default class TreeRepositoryV2 extends BaseRepository { SELECT trees.* FROM trees - LEFT JOIN wallet.token ON token.capture_id::text = lower(trees.uuid) + LEFT JOIN wallet.token ON token.capture_id::text = trees.uuid WHERE wallet.token.wallet_id = '${wallet_id}' LIMIT ${limit} OFFSET ${offset} diff --git a/server/infra/database/WalletsRepository.ts b/server/infra/database/WalletsRepository.ts index 906db3f7..6fd951a3 100644 --- a/server/infra/database/WalletsRepository.ts +++ b/server/infra/database/WalletsRepository.ts @@ -49,7 +49,7 @@ export default class WalletsRepository extends BaseRepository { left join wallet.token on wallet.token.wallet_id = wallet.wallet.id left join public.trees on - wallet.token.capture_id::text = lower(public.trees.uuid::text) + wallet.token.capture_id::text = public.trees.uuid::text left join region as continent on ST_WITHIN(public.trees.estimated_geometric_location, continent.geom) and continent.type_id in (select id from region_type where type = 'continents' ) From cc24027f9ced7a3aee66f8bbf703cc21394206b9 Mon Sep 17 00:00:00 2001 From: Dadiorchen Date: Sat, 27 May 2023 15:53:27 +0800 Subject: [PATCH 15/65] fix: version trigger --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index bfd79637..bbb4c521 100644 --- a/README.md +++ b/README.md @@ -142,3 +142,4 @@ DATABASE_URL=[the link provided] NODE_TLS_REJECT_UNAUTHORIZED='0' npm run test-e . . . +. From 310beef72544989c3edcc9ce8872eadaf8de4a66 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 27 May 2023 07:54:29 +0000 Subject: [PATCH 16/65] chore(release): 1.67.4 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95197607..23e5bb97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.67.4](https://github.com/Greenstand/treetracker-query-api/compare/v1.67.3...v1.67.4) (2023-05-27) + +### Bug Fixes + +- version trigger ([cc24027](https://github.com/Greenstand/treetracker-query-api/commit/cc24027f9ced7a3aee66f8bbf703cc21394206b9)) + ## [1.67.3](https://github.com/Greenstand/treetracker-query-api/compare/v1.67.2...v1.67.3) (2023-05-27) ### Bug Fixes diff --git a/package.json b/package.json index 364e2501..fee0fbb8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.67.3", + "version": "1.67.4", "private": false, "keywords": [ "ecology" From 42463ea321b4656bc66d266069ee5c1c59d9347e Mon Sep 17 00:00:00 2001 From: Dadiorchen Date: Tue, 30 May 2023 10:30:48 +0800 Subject: [PATCH 17/65] docs: how to run dev [skip ci] --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bbb4c521..e273998b 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ npm ci Run the server with database settings: ``` -DATABASE_URL=[...] npm run server +DATABASE_URL=[...] npm run dev ``` Please join our slack channel to get help with setting up the database. From a6bec57ae092529068fd902e6d63d0b4851c3f11 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 2 Jun 2023 09:52:07 +0000 Subject: [PATCH 18/65] feat: git location nearest --- server/app.ts | 2 + server/infra/database/GisRepository.ts | 84 ++++++++++++++++++++++++++ server/models/Gis.ts | 9 +++ server/routers/gisRouter.ts | 34 +++++++++++ 4 files changed, 129 insertions(+) create mode 100644 server/infra/database/GisRepository.ts create mode 100644 server/models/Gis.ts create mode 100644 server/routers/gisRouter.ts diff --git a/server/app.ts b/server/app.ts index 1dfb5372..add01287 100644 --- a/server/app.ts +++ b/server/app.ts @@ -6,6 +6,7 @@ import organizationsRouterV2 from 'routers/organizationsRouterV2'; import boundsRouter from './routers/boundsRouter'; import capturesRouter from './routers/capturesRouter'; import countriesRouter from './routers/countriesRouter'; +import gisRouter from './routers/gisRouter'; import growerAccountsRouter from './routers/growerAccountsRouter'; import organizationsRouter from './routers/organizationsRouter'; import plantersRouter from './routers/plantersRouter'; @@ -77,6 +78,7 @@ app.use('/raw-captures', rawCapturesRouter); app.use('/v2/growers', growerAccountsRouter); app.use('/v2/trees', treesRouterV2); app.use('/bounds', boundsRouter); +app.use('/gis', gisRouter); // Global error handler app.use(errorHandler); diff --git a/server/infra/database/GisRepository.ts b/server/infra/database/GisRepository.ts new file mode 100644 index 00000000..e0d35809 --- /dev/null +++ b/server/infra/database/GisRepository.ts @@ -0,0 +1,84 @@ +import Bounds from 'interfaces/Bounds'; +import HttpError from 'utils/HttpError'; +import Session from './Session'; + +export default class GisRepository { + session: Session; + + constructor(session: Session) { + this.session = session; + } + + async getNearest(params): Promise { + let { zoom_level, lng, lat } = params; + zoom_level = parseInt(zoom_level); + lng = parseFloat(lng); + lat = parseFloat(lat); + console.log('lng:', lng); + let sql; + if (zoom_level <= 11) { + sql = ` + SELECT + ST_ASGeoJson(centroid) + FROM + active_tree_region + WHERE + zoom_level = ${zoom_level} + ORDER BY + active_tree_region.centroid <-> + ST_SetSRID(ST_MakePoint(${lng}, ${lat}),4326) + LIMIT 1; + `; + } else if (zoom_level < 15 && zoom_level > 11) { + sql = ` + SELECT + ST_ASGeoJson(location) + FROM + clusters + ORDER BY + location <-> + ST_SetSRID(ST_MakePoint(${lng}, ${lat}),4326) + LIMIT 1; + `; + } else if (zoom_level >= 15) { + sql = ` + SELECT + ST_ASGeoJson(estimated_geometric_location) + FROM + trees + ${ + params.wallet_id + ? 'join wallet.token on trees.uuid = wallet.token.capture_id::text' + : '' + } + ${ + params.organization_id + ? 'join planter on trees.planter_id = planter.id' + : '' + } + WHERE + active = true + ${ + params.wallet_id ? `and wallet.token.wallet_id = '${params.wallet_id}'` : '' + } + ${params.planter_id ? `and planter_id = ${params.planter_id}` : ''} + ${ + params.organization_id + ? `and planter.organization_id in ( SELECT entity_id from getEntityRelationshipChildren(${params.organization_id}))` + : '' + } + ORDER BY + estimated_geometric_location <-> + ST_SetSRID(ST_MakePoint(${lng}, ${lat}),4326) + LIMIT 1; + `; + } + console.log('query:', sql); + const result = await this.session.getDB().raw(sql); + // {"st_asgeojson":"{\"type\":\"Point\",\"coordinates\":[39.1089215842116,-5.12839483715479]}"} + return { + nearest: + result.rows.length > 0 ? JSON.parse(result.rows[0].st_asgeojson) : null, + }; + } +} diff --git a/server/models/Gis.ts b/server/models/Gis.ts new file mode 100644 index 00000000..72d1ce5b --- /dev/null +++ b/server/models/Gis.ts @@ -0,0 +1,9 @@ +import log from 'loglevel'; +import FilterOptions from 'interfaces/FilterOptions'; +import Tree from 'interfaces/Tree'; +import { delegateRepository } from '../infra/database/delegateRepository'; +import GisRepository from '../infra/database/GisRepository'; + +export default { + getNearest: delegateRepository('getNearest'), +}; diff --git a/server/routers/gisRouter.ts b/server/routers/gisRouter.ts new file mode 100644 index 00000000..8a72723c --- /dev/null +++ b/server/routers/gisRouter.ts @@ -0,0 +1,34 @@ +import { Router, Request, Response } from 'express'; +import Joi from 'joi'; +import BoundsRepository from 'infra/database/BoundsRepository'; +import GisRepository from 'infra/database/GisRepository'; +import Session from 'infra/database/Session'; +import { handlerWrapper } from './utils'; +import BoundsModel from '../models/Bounds'; +import GisModel from '../models/Gis'; + +const router = Router(); +router.get( + '/location/nearest', + handlerWrapper(async (req: Request, res: Response) => { + Joi.assert( + req.query, + Joi.object().keys({ + zoom_level: Joi.number().integer().min(0).required(), + lat: Joi.number().min(-90).max(90).required(), + lng: Joi.number().min(-180).max(180).required(), + wallet_id: Joi.string().uuid().optional(), + planter_id: Joi.number().integer().optional(), + organization_id: Joi.number().integer().optional(), + }), + ); + const repo = new GisRepository(new Session()); + const result = await GisModel.getNearest(repo)(req.query); + res.send({ + nearest: result, + }); + res.end(); + }), +); + +export default router; From 8f99aed0341619181a60f3df76c95acb1c489967 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 2 Jun 2023 09:58:00 +0000 Subject: [PATCH 19/65] chore(release): 1.68.0 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23e5bb97..45bb6fb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# [1.68.0](https://github.com/Greenstand/treetracker-query-api/compare/v1.67.4...v1.68.0) (2023-06-02) + +### Features + +- git location nearest ([a6bec57](https://github.com/Greenstand/treetracker-query-api/commit/a6bec57ae092529068fd902e6d63d0b4851c3f11)) + ## [1.67.4](https://github.com/Greenstand/treetracker-query-api/compare/v1.67.3...v1.67.4) (2023-05-27) ### Bug Fixes diff --git a/package.json b/package.json index fee0fbb8..dede3a5c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.67.4", + "version": "1.68.0", "private": false, "keywords": [ "ecology" From b76abf35c4461d17260a1886f498c5f01ca5ad76 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 3 Jun 2023 06:55:33 +0000 Subject: [PATCH 20/65] fix: bound is wrong to limit the neearest request --- server/infra/database/GisRepository.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/infra/database/GisRepository.ts b/server/infra/database/GisRepository.ts index e0d35809..c934c32a 100644 --- a/server/infra/database/GisRepository.ts +++ b/server/infra/database/GisRepository.ts @@ -42,6 +42,9 @@ export default class GisRepository { `; } else if (zoom_level >= 15) { sql = ` + WITH box AS ( + SELECT ST_Extent(ST_MakeLine(ST_Project(ST_SetSRID(ST_MakePoint(${lng}, ${lat}),4326), 10000, radians(45))::geometry, ST_Project(ST_SetSRID(ST_MakePoint(${lng}, ${lat}),4326), 10000, radians(225))::geometry)) AS geom + ) SELECT ST_ASGeoJson(estimated_geometric_location) FROM @@ -67,6 +70,7 @@ export default class GisRepository { ? `and planter.organization_id in ( SELECT entity_id from getEntityRelationshipChildren(${params.organization_id}))` : '' } + and estimated_geometric_location && (select geom from box) ORDER BY estimated_geometric_location <-> ST_SetSRID(ST_MakePoint(${lng}, ${lat}),4326) From ebe4430a59c4d51313ffd12d655d05946a9702a4 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 3 Jun 2023 06:58:26 +0000 Subject: [PATCH 21/65] chore(release): 1.68.1 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45bb6fb2..d422ac44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.68.1](https://github.com/Greenstand/treetracker-query-api/compare/v1.68.0...v1.68.1) (2023-06-03) + +### Bug Fixes + +- bound is wrong to limit the neearest request ([b76abf3](https://github.com/Greenstand/treetracker-query-api/commit/b76abf35c4461d17260a1886f498c5f01ca5ad76)) + # [1.68.0](https://github.com/Greenstand/treetracker-query-api/compare/v1.67.4...v1.68.0) (2023-06-02) ### Features diff --git a/package.json b/package.json index dede3a5c..29e29bf9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.68.0", + "version": "1.68.1", "private": false, "keywords": [ "ecology" From b4cb0b62fbf9d69aff98585129dabe400b65f010 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 3 Jun 2023 08:18:10 +0000 Subject: [PATCH 22/65] fix: support wallet name, map name, format mistake --- server/infra/database/GisRepository.ts | 20 +++++++++++++------- server/routers/gisRouter.ts | 3 ++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/server/infra/database/GisRepository.ts b/server/infra/database/GisRepository.ts index c934c32a..2a8b72ac 100644 --- a/server/infra/database/GisRepository.ts +++ b/server/infra/database/GisRepository.ts @@ -51,18 +51,20 @@ export default class GisRepository { trees ${ params.wallet_id - ? 'join wallet.token on trees.uuid = wallet.token.capture_id::text' + ? 'join wallet.token on trees.uuid = wallet.token.capture_id::text join wallet.wallet on wallet.token.wallet_id = wallet.wallet.id ' : '' } ${ - params.organization_id + params.organization_id || params.map_name ? 'join planter on trees.planter_id = planter.id' : '' } WHERE active = true ${ - params.wallet_id ? `and wallet.token.wallet_id = '${params.wallet_id}'` : '' + params.wallet_id + ? `and (wallet.token.wallet_id::text = '${params.wallet_id}' or wallet.wallet.name = '${params.wallet_id}')` + : '' } ${params.planter_id ? `and planter_id = ${params.planter_id}` : ''} ${ @@ -70,6 +72,11 @@ export default class GisRepository { ? `and planter.organization_id in ( SELECT entity_id from getEntityRelationshipChildren(${params.organization_id}))` : '' } + ${ + params.map_name + ? `and planter.organization_id in ( SELECT entity_id from getEntityRelationshipChildren((select id from entity where map_name = '${params.map_name}')))` + : '' + } and estimated_geometric_location && (select geom from box) ORDER BY estimated_geometric_location <-> @@ -80,9 +87,8 @@ export default class GisRepository { console.log('query:', sql); const result = await this.session.getDB().raw(sql); // {"st_asgeojson":"{\"type\":\"Point\",\"coordinates\":[39.1089215842116,-5.12839483715479]}"} - return { - nearest: - result.rows.length > 0 ? JSON.parse(result.rows[0].st_asgeojson) : null, - }; + return result.rows.length > 0 + ? JSON.parse(result.rows[0].st_asgeojson) + : null; } } diff --git a/server/routers/gisRouter.ts b/server/routers/gisRouter.ts index 8a72723c..e3480e59 100644 --- a/server/routers/gisRouter.ts +++ b/server/routers/gisRouter.ts @@ -17,9 +17,10 @@ router.get( zoom_level: Joi.number().integer().min(0).required(), lat: Joi.number().min(-90).max(90).required(), lng: Joi.number().min(-180).max(180).required(), - wallet_id: Joi.string().uuid().optional(), + wallet_id: Joi.string().optional(), planter_id: Joi.number().integer().optional(), organization_id: Joi.number().integer().optional(), + map_name: Joi.string().optional(), }), ); const repo = new GisRepository(new Session()); From f97f53ea2c259ffb94805f09a423352a5f72b9d6 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 3 Jun 2023 08:20:58 +0000 Subject: [PATCH 23/65] chore(release): 1.68.2 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d422ac44..c2bcf7d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.68.2](https://github.com/Greenstand/treetracker-query-api/compare/v1.68.1...v1.68.2) (2023-06-03) + +### Bug Fixes + +- support wallet name, map name, format mistake ([b4cb0b6](https://github.com/Greenstand/treetracker-query-api/commit/b4cb0b62fbf9d69aff98585129dabe400b65f010)) + ## [1.68.1](https://github.com/Greenstand/treetracker-query-api/compare/v1.68.0...v1.68.1) (2023-06-03) ### Bug Fixes diff --git a/package.json b/package.json index 29e29bf9..57bf0f2b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.68.1", + "version": "1.68.2", "private": false, "keywords": [ "ecology" From 8e1182a96a7c6d766ddae8add2affd376dcbf7f7 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 4 Jun 2023 06:49:51 +0000 Subject: [PATCH 24/65] feat: neartest wallet case --- .eslintrc.js | 1 + server/infra/database/GisRepository.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.eslintrc.js b/.eslintrc.js index 7995454e..020b3396 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -12,6 +12,7 @@ module.exports = { rules: { // disabled or modified because too strict + 'no-nested-ternary': 'off', 'no-restricted-globals': 'warn', 'no-console': ['warn', { allow: ['info', 'error'] }], 'import/prefer-default-export': 'off', diff --git a/server/infra/database/GisRepository.ts b/server/infra/database/GisRepository.ts index 2a8b72ac..79958622 100644 --- a/server/infra/database/GisRepository.ts +++ b/server/infra/database/GisRepository.ts @@ -63,7 +63,9 @@ export default class GisRepository { active = true ${ params.wallet_id - ? `and (wallet.token.wallet_id::text = '${params.wallet_id}' or wallet.wallet.name = '${params.wallet_id}')` + ? /[0-9a-f-]{36}/.test(params.wallet_id) + ? `and wallet.token.wallet_id = '${params.wallet_id}' ` + : `and wallet.wallet.name = '${params.wallet_id}'` : '' } ${params.planter_id ? `and planter_id = ${params.planter_id}` : ''} From 341bf732ba9b0feafc5b51b08e638eb09308e2d8 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sun, 4 Jun 2023 06:54:23 +0000 Subject: [PATCH 25/65] chore(release): 1.69.0 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2bcf7d1..e2c37983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# [1.69.0](https://github.com/Greenstand/treetracker-query-api/compare/v1.68.2...v1.69.0) (2023-06-04) + +### Features + +- neartest wallet case ([8e1182a](https://github.com/Greenstand/treetracker-query-api/commit/8e1182a96a7c6d766ddae8add2affd376dcbf7f7)) + ## [1.68.2](https://github.com/Greenstand/treetracker-query-api/compare/v1.68.1...v1.68.2) (2023-06-03) ### Bug Fixes diff --git a/package.json b/package.json index 57bf0f2b..308401e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.68.2", + "version": "1.69.0", "private": false, "keywords": [ "ecology" From 7cdeb02c4deaab7443119a5e3c5a28efed984864 Mon Sep 17 00:00:00 2001 From: Mayank Bucha Date: Sun, 11 Jun 2023 23:25:23 +0530 Subject: [PATCH 26/65] fix: shows only acitve trees for GET /tokens resolves #322 --- server/infra/database/TokensRepository.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/infra/database/TokensRepository.ts b/server/infra/database/TokensRepository.ts index 89fe7d59..0ae72318 100644 --- a/server/infra/database/TokensRepository.ts +++ b/server/infra/database/TokensRepository.ts @@ -89,10 +89,13 @@ export default class TokensRepository extends BaseRepository { const sql = `SELECT COUNT(*) from wallet.token as wlt_tkn + left join public.trees on + public.trees.uuid::text = wlt_tkn.capture_id::text left join wallet.wallet as wlt_wallet on wlt_wallet.id = wlt_tkn.wallet_id where wlt_wallet.id::text = '${filter.wallet}' or - wlt_wallet.name = '${filter.wallet}' + wlt_wallet.name = '${filter.wallet} and + public.trees.active = true' `; const total = await this.session.getDB().raw(sql); return parseInt(total.rows[0].count.toString());; From 0a8c75047caad9a64b62a2a2949d9304e04ff936 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 15 Jun 2023 08:56:10 +0000 Subject: [PATCH 27/65] chore(release): 1.69.1 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2c37983..ebdeb0a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.69.1](https://github.com/Greenstand/treetracker-query-api/compare/v1.69.0...v1.69.1) (2023-06-15) + +### Bug Fixes + +- shows only acitve trees for GET /tokens ([7cdeb02](https://github.com/Greenstand/treetracker-query-api/commit/7cdeb02c4deaab7443119a5e3c5a28efed984864)), closes [#322](https://github.com/Greenstand/treetracker-query-api/issues/322) + # [1.69.0](https://github.com/Greenstand/treetracker-query-api/compare/v1.68.2...v1.69.0) (2023-06-04) ### Features diff --git a/package.json b/package.json index 308401e8..2326a2c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.69.0", + "version": "1.69.1", "private": false, "keywords": [ "ecology" From 20f0f40e9781ad6e57303c484479bf9996547e18 Mon Sep 17 00:00:00 2001 From: Dadiorchen Date: Fri, 16 Jun 2023 09:50:17 +0800 Subject: [PATCH 28/65] Revert "fix: shows only acitve trees for GET /tokens" --- server/infra/database/TokensRepository.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/server/infra/database/TokensRepository.ts b/server/infra/database/TokensRepository.ts index 0ae72318..89fe7d59 100644 --- a/server/infra/database/TokensRepository.ts +++ b/server/infra/database/TokensRepository.ts @@ -89,13 +89,10 @@ export default class TokensRepository extends BaseRepository { const sql = `SELECT COUNT(*) from wallet.token as wlt_tkn - left join public.trees on - public.trees.uuid::text = wlt_tkn.capture_id::text left join wallet.wallet as wlt_wallet on wlt_wallet.id = wlt_tkn.wallet_id where wlt_wallet.id::text = '${filter.wallet}' or - wlt_wallet.name = '${filter.wallet} and - public.trees.active = true' + wlt_wallet.name = '${filter.wallet}' `; const total = await this.session.getDB().raw(sql); return parseInt(total.rows[0].count.toString());; From dd014e8daf50b18726ff5995ba9dad716fd93285 Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Wed, 21 Jun 2023 19:20:50 +0530 Subject: [PATCH 29/65] Update PlanterRepository.ts --- server/infra/database/PlanterRepository.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/infra/database/PlanterRepository.ts b/server/infra/database/PlanterRepository.ts index f5b62cff..18695f1a 100644 --- a/server/infra/database/PlanterRepository.ts +++ b/server/infra/database/PlanterRepository.ts @@ -23,6 +23,7 @@ export default class PlanterRepository extends BaseRepository { planter_registrations.created_at as created_at from planter left join planter_registrations on planter.id = planter_registrations.planter_id + AND planter_registrations.created_at = (Select Min(created_at) from planter_registrations planter_registrations.planter_id=planter.id) LEFT JOIN webmap.planter_location l ON l.id = planter.id `), ) @@ -101,6 +102,7 @@ export default class PlanterRepository extends BaseRepository { FROM planter LEFT JOIN planter_registrations ON planter.id = planter_registrations.planter_id + AND planter_registrations.created_at = (Select Min(created_at) from planter_registrations as planter_reg where planter_reg.planter_id=planter.id) LEFT JOIN webmap.planter_location l ON l.id = planter.id ${ options.orderBy @@ -124,7 +126,7 @@ export default class PlanterRepository extends BaseRepository { FROM planter LEFT JOIN planter_registrations ON planter.id = planter_registrations.planter_id - LEFT JOIN webmap.planter_location l ON l.id = planter.id + AND planter_registrations.created_at = (Select Min(created_at) from planter_registrations as planter_reg where planter_reg.planter_id=planter.id) LEFT JOIN webmap.planter_location l ON l.id = planter.id WHERE planter.first_name LIKE '${keyword}%' OR planter.last_name LIKE '${keyword}%' ORDER BY planter.first_name, planter.last_name LIMIT ${limit} From 29e54df93691b97a257224328fdc8e8a4fa3f6d1 Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Wed, 21 Jun 2023 19:23:46 +0530 Subject: [PATCH 30/65] Update PlanterRepository.ts --- server/infra/database/PlanterRepository.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/server/infra/database/PlanterRepository.ts b/server/infra/database/PlanterRepository.ts index 18695f1a..0ef26acd 100644 --- a/server/infra/database/PlanterRepository.ts +++ b/server/infra/database/PlanterRepository.ts @@ -53,6 +53,7 @@ export default class PlanterRepository extends BaseRepository { FROM planter LEFT JOIN planter_registrations ON planter.id = planter_registrations.planter_id + AND planter_registrations.created_at = (Select Min(created_at) from planter_registrations planter_registrations.planter_id=planter.id) LEFT JOIN webmap.planter_location l ON l.id = planter.id WHERE planter.organization_id in (select entity_id from getEntityRelationshipChildren(${organization_id})) ${ From e3f429374e2e7d73ea7adaf67a1f9489a5466ac3 Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Thu, 22 Jun 2023 10:36:26 +0530 Subject: [PATCH 31/65] Update PlanterRepository.ts --- server/infra/database/PlanterRepository.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/infra/database/PlanterRepository.ts b/server/infra/database/PlanterRepository.ts index 0ef26acd..2113f716 100644 --- a/server/infra/database/PlanterRepository.ts +++ b/server/infra/database/PlanterRepository.ts @@ -23,7 +23,7 @@ export default class PlanterRepository extends BaseRepository { planter_registrations.created_at as created_at from planter left join planter_registrations on planter.id = planter_registrations.planter_id - AND planter_registrations.created_at = (Select Min(created_at) from planter_registrations planter_registrations.planter_id=planter.id) + AND planter_registrations.created_at = (Select Min(created_at) from planter_registrations as planter_reg where planter_reg.planter_id=planter.id) LEFT JOIN webmap.planter_location l ON l.id = planter.id `), ) @@ -53,7 +53,7 @@ export default class PlanterRepository extends BaseRepository { FROM planter LEFT JOIN planter_registrations ON planter.id = planter_registrations.planter_id - AND planter_registrations.created_at = (Select Min(created_at) from planter_registrations planter_registrations.planter_id=planter.id) + AND planter_registrations.created_at = (Select Min(created_at) from planter_registrations as planter_reg where planter_reg.planter_id=planter.id) LEFT JOIN webmap.planter_location l ON l.id = planter.id WHERE planter.organization_id in (select entity_id from getEntityRelationshipChildren(${organization_id})) ${ From bb78aedd223178abcebdfddb7df4d6aa2d8828ff Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Tue, 27 Jun 2023 19:07:30 +0530 Subject: [PATCH 32/65] organization_id --- .../infra/database/OrganizationRepository.ts | 22 ++++++++ .../database/OrganizationRepositoryV2.ts | 56 +++++++++++++++++++ server/models/Organization.ts | 10 +++- server/routers/organizationsRouterV2.ts | 7 ++- 4 files changed, 92 insertions(+), 3 deletions(-) diff --git a/server/infra/database/OrganizationRepository.ts b/server/infra/database/OrganizationRepository.ts index e0fb7d92..178af4b1 100644 --- a/server/infra/database/OrganizationRepository.ts +++ b/server/infra/database/OrganizationRepository.ts @@ -32,6 +32,28 @@ export default class OrganizationRepository extends BaseRepository return objectPatched; } + async getByGrower(grower_id: string, options: FilterOptions) { + const { limit, offset } = options; + const sql = ` + SELECT + entity.*, + l.country_id, l.country_name, l.continent_id, l.continent_name + FROM entity + LEFT JOIN webmap.organization_location l ON l.id = entity.id + LEFT JOIN planter ON planter.organization_id = entity.id + WHERE planter.grower_account_uuid = ${grower_id} + LIMIT ${limit} + OFFSET ${offset} + `; + const object = await this.session.getDB().raw(sql); + const objectPatched = await patch( + object.rows, + PATCH_TYPE.EXTRA_ORG, + this.session, + ); + return objectPatched; + } + async getById(id: string | number) { const object = await this.session .getDB() diff --git a/server/infra/database/OrganizationRepositoryV2.ts b/server/infra/database/OrganizationRepositoryV2.ts index 01895d73..ff808989 100644 --- a/server/infra/database/OrganizationRepositoryV2.ts +++ b/server/infra/database/OrganizationRepositoryV2.ts @@ -9,8 +9,19 @@ export default class OrganizationRepositoryV2 extends BaseRepository; +type Filter = Partial<{ planter_id: number; organization_id: number, grower_id:string }>; function getByFilter( organizationRepository: OrganizationRepository, @@ -18,6 +18,14 @@ function getByFilter( ); return trees; } + else if (filter.grower_id){ + log.warn('using planter filter...'); + const trees = await organizationRepository.getByGrower( + filter.grower_id, + options, + ); + return trees; + } const trees = await organizationRepository.getByFilter(filter, options); return trees; }; diff --git a/server/routers/organizationsRouterV2.ts b/server/routers/organizationsRouterV2.ts index 141d2f39..f340d943 100644 --- a/server/routers/organizationsRouterV2.ts +++ b/server/routers/organizationsRouterV2.ts @@ -5,7 +5,7 @@ import OrganizationRepositoryV2 from '../infra/database/OrganizationRepositoryV2 import Session from '../infra/database/Session'; import OrganizationModel from '../models/Organization'; -type Filter = Partial<{ planter_id: number; organization_id: number }>; +type Filter = Partial<{ planter_id: number; organization_id: number, grower_id:string }>; const router = express.Router(); @@ -51,15 +51,18 @@ router.get( req.query, Joi.object().keys({ planter_id: Joi.number().integer().min(0), + grower_id:Joi.string(), limit: Joi.number().integer().min(1).max(1000), offset: Joi.number().integer().min(0), }), ); - const { limit = 20, offset = 0, planter_id } = req.query; + const { limit = 20, offset = 0, planter_id, grower_id } = req.query; const repo = new OrganizationRepositoryV2(new Session()); const filter: Filter = {}; if (planter_id) { filter.planter_id = planter_id; + } else if(grower_id){ + filter.grower_id = grower_id; } const result = await OrganizationModel.getByFilter(repo)(filter, { limit, From 57a3cd9b03404e8e109d78731c4063855c0e01e8 Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Tue, 27 Jun 2023 19:10:26 +0530 Subject: [PATCH 33/65] bug_fix --- server/infra/database/OrganizationRepositoryV2.ts | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/server/infra/database/OrganizationRepositoryV2.ts b/server/infra/database/OrganizationRepositoryV2.ts index ff808989..cd3e6c48 100644 --- a/server/infra/database/OrganizationRepositoryV2.ts +++ b/server/infra/database/OrganizationRepositoryV2.ts @@ -9,19 +9,8 @@ export default class OrganizationRepositoryV2 extends BaseRepository Date: Tue, 27 Jun 2023 19:26:03 +0530 Subject: [PATCH 34/65] bug_fix --- server/models/Organization.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/models/Organization.ts b/server/models/Organization.ts index 511b7887..724af234 100644 --- a/server/models/Organization.ts +++ b/server/models/Organization.ts @@ -18,7 +18,7 @@ function getByFilter( ); return trees; } - else if (filter.grower_id){ + if (filter.grower_id){ log.warn('using planter filter...'); const trees = await organizationRepository.getByGrower( filter.grower_id, From 03df388fc632c121b40d2f580e09e615f6e3648f Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Thu, 29 Jun 2023 18:43:45 +0530 Subject: [PATCH 35/65] Organization --- .../infra/database/OrganizationRepository.ts | 22 -------- server/models/Organization.ts | 11 +--- server/models/OrganizationV2.ts | 54 +++++++++++++++++++ server/routers/organizationsRouterV2.ts | 2 +- 4 files changed, 57 insertions(+), 32 deletions(-) create mode 100644 server/models/OrganizationV2.ts diff --git a/server/infra/database/OrganizationRepository.ts b/server/infra/database/OrganizationRepository.ts index 178af4b1..e0fb7d92 100644 --- a/server/infra/database/OrganizationRepository.ts +++ b/server/infra/database/OrganizationRepository.ts @@ -32,28 +32,6 @@ export default class OrganizationRepository extends BaseRepository return objectPatched; } - async getByGrower(grower_id: string, options: FilterOptions) { - const { limit, offset } = options; - const sql = ` - SELECT - entity.*, - l.country_id, l.country_name, l.continent_id, l.continent_name - FROM entity - LEFT JOIN webmap.organization_location l ON l.id = entity.id - LEFT JOIN planter ON planter.organization_id = entity.id - WHERE planter.grower_account_uuid = ${grower_id} - LIMIT ${limit} - OFFSET ${offset} - `; - const object = await this.session.getDB().raw(sql); - const objectPatched = await patch( - object.rows, - PATCH_TYPE.EXTRA_ORG, - this.session, - ); - return objectPatched; - } - async getById(id: string | number) { const object = await this.session .getDB() diff --git a/server/models/Organization.ts b/server/models/Organization.ts index 724af234..d011c297 100644 --- a/server/models/Organization.ts +++ b/server/models/Organization.ts @@ -4,7 +4,7 @@ import Organization from 'interfaces/Organization'; import { delegateRepository } from '../infra/database/delegateRepository'; import OrganizationRepository from '../infra/database/OrganizationRepository'; -type Filter = Partial<{ planter_id: number; organization_id: number, grower_id:string }>; +type Filter = Partial<{ planter_id: number; organization_id: number}>; function getByFilter( organizationRepository: OrganizationRepository, @@ -18,14 +18,7 @@ function getByFilter( ); return trees; } - if (filter.grower_id){ - log.warn('using planter filter...'); - const trees = await organizationRepository.getByGrower( - filter.grower_id, - options, - ); - return trees; - } + const trees = await organizationRepository.getByFilter(filter, options); return trees; }; diff --git a/server/models/OrganizationV2.ts b/server/models/OrganizationV2.ts new file mode 100644 index 00000000..445e5f94 --- /dev/null +++ b/server/models/OrganizationV2.ts @@ -0,0 +1,54 @@ +import log from 'loglevel'; +import OrganizationRepositoryV2 from 'infra/database/OrganizationRepositoryV2'; +import FilterOptions from 'interfaces/FilterOptions'; +import Organization from 'interfaces/Organization'; +import { delegateRepository } from '../infra/database/delegateRepository'; + +type Filter = Partial<{ planter_id: number; organization_id: number, grower_id:string }>; + +function getByFilter( + organizationRepository: OrganizationRepositoryV2, +): (filter: Filter, options: FilterOptions) => Promise { + return async function (filter: Filter, options: FilterOptions) { + if (filter.planter_id) { + log.warn('using planter filter...'); + const trees = await organizationRepository.getByPlanter( + filter.planter_id, + options, + ); + return trees; + } + if (filter.grower_id){ + log.warn('using planter filter...'); + const trees = await organizationRepository.getByGrower( + filter.grower_id, + options, + ); + return trees; + } + const trees = await organizationRepository.getByFilter(filter, options); + return trees; + }; +} + +function getOrganizationLinks(organization) { + const links = { + featured_trees: `/trees?organization_id=${organization.id}&limit=20&offset=0`, + associated_planters: `/planters?organization_id=${organization.id}&limit=20&offset=0`, + species: `/species?organization_id=${organization.id}&limit=20&offset=0`, + }; + return links; +} + +export default { + getById: delegateRepository('getById'), + getByMapName: delegateRepository( + 'getByMapName', + ), + getByFilter, + getOrganizationLinks, + getFeaturedOrganizations: delegateRepository< + OrganizationRepositoryV2, + Organization + >('getFeaturedOrganizations'), +}; \ No newline at end of file diff --git a/server/routers/organizationsRouterV2.ts b/server/routers/organizationsRouterV2.ts index f340d943..f813a774 100644 --- a/server/routers/organizationsRouterV2.ts +++ b/server/routers/organizationsRouterV2.ts @@ -3,7 +3,7 @@ import Joi from 'joi'; import { handlerWrapper } from './utils'; import OrganizationRepositoryV2 from '../infra/database/OrganizationRepositoryV2'; import Session from '../infra/database/Session'; -import OrganizationModel from '../models/Organization'; +import OrganizationModel from '../models/OrganizationV2'; type Filter = Partial<{ planter_id: number; organization_id: number, grower_id:string }>; From 481707d0d434fc47b4acfecff9bb469b403ef453 Mon Sep 17 00:00:00 2001 From: Olojakpoke Daniel Date: Mon, 3 Jul 2023 22:00:42 +0100 Subject: [PATCH 36/65] fix: wallet about --- package.json | 2 +- server/infra/database/WalletsRepository.ts | 16 ++++++++++------ server/infra/database/patch.ts | 9 ++++++++- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 2326a2c9..000e58c4 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "prepare": "husky install", "server-test": "DEBUG=express:* NODE_LOG_LEVEL=debug nodemon server/serverTest.js", "start": "NODE_TLS_REJECT_UNAUTHORIZED='0' NODE_PATH=dist/ node dist/server.js", - "start:dev": "NODE_PATH=server/ ts-node -r dotenv/config --project tsconfig.build.json server/server.ts", + "start:dev": "cross-env NODE_PATH=server/ ts-node -r dotenv/config --project tsconfig.build.json server/server.ts", "test": "npm run test-unit; npm run test-integration;npm run test-repository", "test-e2e": "jest ./__tests__/e2e/", "test-integration": "NODE_ENV=test mocha -r dotenv/config dotenv_config_path=.env.test --exit --timeout 20000 './__tests__/supertest.js'", diff --git a/server/infra/database/WalletsRepository.ts b/server/infra/database/WalletsRepository.ts index 6fd951a3..3514a5f0 100644 --- a/server/infra/database/WalletsRepository.ts +++ b/server/infra/database/WalletsRepository.ts @@ -18,7 +18,8 @@ export default class WalletsRepository extends BaseRepository { wallet.wallet.id, wallet.wallet.name, wallet.wallet.logo_url, - wallet.wallet.created_at + wallet.wallet.created_at, + wallet.wallet.about FROM wallet.wallet WHERE @@ -44,7 +45,7 @@ export default class WalletsRepository extends BaseRepository { async getWalletTokenContinentCount(walletIdOrName: string) { const sql = ` - select continent.name as continent ,count(continent.name) as token_count + select continent.name as continent , wallet.wallet.about, count(continent.name) as token_count from wallet.wallet left join wallet.token on wallet.token.wallet_id = wallet.wallet.id @@ -55,7 +56,7 @@ export default class WalletsRepository extends BaseRepository { and continent.type_id in (select id from region_type where type = 'continents' ) where wallet.wallet.id::text = '${walletIdOrName}' or wallet.wallet.name = '${walletIdOrName}' - group by continent.name + group by continent.name, wallet.about `; const object = await this.session.getDB().raw(sql); @@ -75,7 +76,8 @@ export default class WalletsRepository extends BaseRepository { wallet.wallet.id, wallet.wallet.name, wallet.wallet.logo_url, - wallet.wallet.created_at + wallet.wallet.created_at, + wallet.wallet.about FROM wallet.wallet LIMIT ${limit} OFFSET ${offset} @@ -96,7 +98,8 @@ export default class WalletsRepository extends BaseRepository { wallet.wallet.id, wallet.wallet.name, wallet.wallet.logo_url, - wallet.wallet.created_at + wallet.wallet.created_at, + wallet.wallet.about FROM wallet.wallet WHERE name LIKE '%${keyword}%' ORDER BY name @@ -118,7 +121,8 @@ export default class WalletsRepository extends BaseRepository { wallet.wallet.id as id, wallet.wallet.name, wallet.wallet.logo_url, - wallet.wallet.created_at + wallet.wallet.created_at, + wallet.wallet.about FROM wallet.wallet join ( --- convert json array to row diff --git a/server/infra/database/patch.ts b/server/infra/database/patch.ts index 697e73a5..77bd7e80 100644 --- a/server/infra/database/patch.ts +++ b/server/infra/database/patch.ts @@ -43,6 +43,9 @@ async function patch(object: any, patchType: PATCH_TYPE, session: Session) { object.forEach((o) => { const extra = res.rows.find((r) => r.ref_id === o.id); if (extra) { + if (patchType === PATCH_TYPE.EXTRA_WALLET) { + delete extra.data?.about; + } result.push({ ...o, ...extra.data }); } else { result.push(o); @@ -57,7 +60,11 @@ async function patch(object: any, patchType: PATCH_TYPE, session: Session) { if (res.rows.length === 1) { log.debug('found result, patch'); - result = { ...object, ...res.rows[0].data }; + const patchData = res.rows[0]; + if (patchType === PATCH_TYPE.EXTRA_WALLET) { + delete patchData.data?.about; + } + result = { ...object, ...patchData.data }; } } From ffd264a0f78d003fb004eef6759ef53032b01994 Mon Sep 17 00:00:00 2001 From: Olojakpoke Daniel Date: Tue, 4 Jul 2023 02:38:19 +0100 Subject: [PATCH 37/65] fix: minor update --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 000e58c4..2326a2c9 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "prepare": "husky install", "server-test": "DEBUG=express:* NODE_LOG_LEVEL=debug nodemon server/serverTest.js", "start": "NODE_TLS_REJECT_UNAUTHORIZED='0' NODE_PATH=dist/ node dist/server.js", - "start:dev": "cross-env NODE_PATH=server/ ts-node -r dotenv/config --project tsconfig.build.json server/server.ts", + "start:dev": "NODE_PATH=server/ ts-node -r dotenv/config --project tsconfig.build.json server/server.ts", "test": "npm run test-unit; npm run test-integration;npm run test-repository", "test-e2e": "jest ./__tests__/e2e/", "test-integration": "NODE_ENV=test mocha -r dotenv/config dotenv_config_path=.env.test --exit --timeout 20000 './__tests__/supertest.js'", From 0b46dd778195140352b99b24f97b66dd3e4ada90 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 4 Jul 2023 01:42:39 +0000 Subject: [PATCH 38/65] chore(release): 1.69.2 [skip ci] --- CHANGELOG.md | 7 +++++++ package.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebdeb0a3..843560f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [1.69.2](https://github.com/Greenstand/treetracker-query-api/compare/v1.69.1...v1.69.2) (2023-07-04) + +### Bug Fixes + +- minor update ([ffd264a](https://github.com/Greenstand/treetracker-query-api/commit/ffd264a0f78d003fb004eef6759ef53032b01994)) +- wallet about ([481707d](https://github.com/Greenstand/treetracker-query-api/commit/481707d0d434fc47b4acfecff9bb469b403ef453)) + ## [1.69.1](https://github.com/Greenstand/treetracker-query-api/compare/v1.69.0...v1.69.1) (2023-06-15) ### Bug Fixes diff --git a/package.json b/package.json index 2326a2c9..04d0223b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.69.1", + "version": "1.69.2", "private": false, "keywords": [ "ecology" From 3678d696a39d70ff334fcc8c685fdfc330da3eee Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Wed, 12 Jul 2023 22:20:42 +0530 Subject: [PATCH 39/65] tree uuid --- server/infra/database/TreeRepository.ts | 44 ++++++++- server/models/Tree.ts | 1 + server/models/TreeV2.ts | 121 ++++++++++++++++++++++++ server/routers/treesRouter.ts | 16 +++- server/routers/treesRouterV2.ts | 2 +- 5 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 server/models/TreeV2.ts diff --git a/server/infra/database/TreeRepository.ts b/server/infra/database/TreeRepository.ts index e7775875..0f508f34 100644 --- a/server/infra/database/TreeRepository.ts +++ b/server/infra/database/TreeRepository.ts @@ -9,7 +9,7 @@ export default class TreeRepository extends BaseRepository { super('trees', session); } - async getById(id: string | number) { + async getById(id: number) { const object = await this.session .getDB() .select( @@ -50,6 +50,48 @@ export default class TreeRepository extends BaseRepository { return object; } + async getByUUID(uuid: string) { + const object = await this.session + .getDB() + .select( + this.session.getDB().raw(` + trees.*, + tree_species.id as species_id, + tree_species.name as species_name, + tree_species.desc as species_desc, + region.name as country_name, + region.id as country_id, + entity.id as organization_id, + entity.name as organization_name, + wallet.wallet.id as wallet_id, + wallet.wallet.name as wallet_name, + wallet.token.id as token_id + from trees + left JOIN planter + on trees.planter_id = planter.id + left JOIN entity + on entity.id = planter.organization_id + left JOIN tree_species + on trees.species_id = tree_species.id + left JOIN region + on ST_WITHIN(trees.estimated_geometric_location, region.geom) + and region.type_id in (select id from region_type where type = 'country') + left JOIN wallet.token + on wallet.token.capture_id::text = trees.uuid::text + left JOIN wallet.wallet + on wallet.token.wallet_id = wallet.wallet.id + `), + ) + .where('trees.uuid', uuid) + .first(); + + if (!object) { + throw new HttpError(404, `Can not find ${this.tableName} by uuid:${uuid}`); + } + return object; + } + + async getByOrganization( organization_id: number, options: FilterOptions, diff --git a/server/models/Tree.ts b/server/models/Tree.ts index 421a585c..369b7de0 100644 --- a/server/models/Tree.ts +++ b/server/models/Tree.ts @@ -115,6 +115,7 @@ function getFeaturedTreeDepricated(treeRepository: TreeRepository) { export default { getById: delegateRepository('getById'), + getByUUID: delegateRepository('getByUUID'), getByFilter, getFeaturedTree: delegateRepository('getFeaturedTree'), countByFilter, diff --git a/server/models/TreeV2.ts b/server/models/TreeV2.ts new file mode 100644 index 00000000..f6365e8e --- /dev/null +++ b/server/models/TreeV2.ts @@ -0,0 +1,121 @@ +import log from 'loglevel'; +import FilterOptions from 'interfaces/FilterOptions'; +import Tree from 'interfaces/Tree'; +import { delegateRepository } from '../infra/database/delegateRepository'; +import TreeRepositoryV2 from '../infra/database/TreeRepositoryV2'; + +type Filter = Partial<{ + organization_id: number; + date_range: { startDate: string; endDate: string }; + tag: string; + wallet_id: string; +}>; + +function getByFilter( + treeRepository: TreeRepositoryV2, +): (filter: Filter, options: FilterOptions) => Promise { + return async function (filter: Filter, options: FilterOptions) { + if (filter.organization_id) { + log.warn('using org filter...'); + const trees = await treeRepository.getByOrganization( + filter.organization_id, + options, + ); + return trees; + } + if (filter.date_range) { + log.warn('using date range filter...'); + const trees = await treeRepository.getByDateRange( + filter.date_range, + options, + ); + return trees; + } + if (filter.tag) { + log.warn('using tag filter...'); + const trees = await treeRepository.getByTag(filter.tag, options); + return trees; + } + if (filter.wallet_id) { + log.warn('using wallet filter...'); + const trees = await treeRepository.getByWallet(filter.wallet_id, options); + return trees; + } + + const trees = await treeRepository.getByFilter(filter, options); + return trees; + }; +} + +function countByFilter( + treeRepository: TreeRepositoryV2, +): (filter: Filter, options: FilterOptions) => Promise { + return async function (filter: Filter, options: FilterOptions) { + if (filter.organization_id) { + log.warn('using org filter...'); + const total = await treeRepository.getByOrganization( + filter.organization_id, + options, + true, + ); + return total; + } + if (filter.date_range) { + log.warn('using date range filter...'); + const total = await treeRepository.getByDateRange( + filter.date_range, + options, + true, + ); + return total; + } + if (filter.tag) { + log.warn('using tag filter...'); + const total = await treeRepository.getByTag(filter.tag, options, true); + return total; + } + if (filter.wallet_id) { + log.warn('using wallet filter...'); + const total = await treeRepository.getByWallet( + filter.wallet_id, + options, + true, + ); + return total; + } + + const total = await treeRepository.countByFilter(filter); + return total; + }; +} + +/* + featured tree, some highlighted tree, for a tempororily solution + we just put the newest, verified tree + */ +function getFeaturedTreeDepricated(treeRepository: TreeRepositoryV2) { + return async () => { + // const trees = await treeRepository.getByFilter( + // { + // approved: true, + // }, + // { limit: 10, orderBy: { column: 'time_created', direction: 'desc' } }, + // ); + // + const trees: Array = []; + // eslint-disable-next-line no-restricted-syntax + for (const id of [186737, 186735, 186736, 186734]) { + // eslint-disable-next-line no-await-in-loop + const tree = await treeRepository.getById(id); + trees.push(tree); + } + return trees; + }; +} + +export default { + getById: delegateRepository('getById'), + getByFilter, + getFeaturedTree: delegateRepository('getFeaturedTree'), + countByFilter, +}; \ No newline at end of file diff --git a/server/routers/treesRouter.ts b/server/routers/treesRouter.ts index 9a082ab7..343f2a3d 100644 --- a/server/routers/treesRouter.ts +++ b/server/routers/treesRouter.ts @@ -31,17 +31,25 @@ router.get( ); router.get( - '/:id', + '/:val', handlerWrapper(async (req, res) => { - Joi.assert(req.params.id, Joi.number().required()); const repo = new TreeRepository(new Session()); - const exe = TreeModel.getById(repo); - const result = await exe(req.params.id); + let result + if(isNaN(Number(req.params.val))){ + Joi.assert(req.params.val, Joi.string().required()); + const exe = TreeModel.getByUUID(repo); + result = await exe(req.params.val); + } else{ + Joi.assert(req.params.val, Joi.number().required()); + const exe = TreeModel.getById(repo); + result = await exe(req.params.val); + } res.send(result); res.end(); }), ); + router.get( '/', handlerWrapper(async (req, res) => { diff --git a/server/routers/treesRouterV2.ts b/server/routers/treesRouterV2.ts index 52e5c8f3..2ea47dc2 100644 --- a/server/routers/treesRouterV2.ts +++ b/server/routers/treesRouterV2.ts @@ -5,7 +5,7 @@ import Tree from 'interfaces/Tree'; import { handlerWrapper } from './utils'; import Session from '../infra/database/Session'; import TreeRepositoryV2 from '../infra/database/TreeRepositoryV2'; -import TreeModel from '../models/Tree'; +import TreeModel from '../models/TreeV2'; const router = express.Router(); type Filter = Partial<{ From 2fbd88122bafcf0ec871c0969894a74eafdb89a0 Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:32:07 +0530 Subject: [PATCH 40/65] GUID option --- server/routers/treesRouter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/treesRouter.ts b/server/routers/treesRouter.ts index 343f2a3d..9de19399 100644 --- a/server/routers/treesRouter.ts +++ b/server/routers/treesRouter.ts @@ -36,7 +36,7 @@ router.get( const repo = new TreeRepository(new Session()); let result if(isNaN(Number(req.params.val))){ - Joi.assert(req.params.val, Joi.string().required()); + Joi.assert(req.params.val, Joi.string().guid().required()); const exe = TreeModel.getByUUID(repo); result = await exe(req.params.val); } else{ From 2166c4660bc94c851fbb70a3e70b550e7428f81a Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Fri, 14 Jul 2023 22:52:46 +0530 Subject: [PATCH 41/65] Species and Organization --- server/app.ts | 3 +- server/infra/database/SpeciesRepositoryV2.ts | 122 +++++++++++++++++++ server/models/OrganizationV2.ts | 2 +- server/models/SpeciesV2.ts | 61 ++++++++++ server/routers/organizationsRouterV2.ts | 2 +- server/routers/speciesRouterV2.ts | 78 ++++++++++++ 6 files changed, 265 insertions(+), 3 deletions(-) create mode 100644 server/infra/database/SpeciesRepositoryV2.ts create mode 100644 server/models/SpeciesV2.ts create mode 100644 server/routers/speciesRouterV2.ts diff --git a/server/app.ts b/server/app.ts index add01287..efbd18ba 100644 --- a/server/app.ts +++ b/server/app.ts @@ -12,6 +12,7 @@ import organizationsRouter from './routers/organizationsRouter'; import plantersRouter from './routers/plantersRouter'; import rawCapturesRouter from './routers/rawCapturesRouter'; import speciesRouter from './routers/speciesRouter'; +import speciesRouterV2 from './routers/speciesRouterV2'; import tokensRouter from './routers/tokensRouter'; import transactionsRouter from './routers/transactionsRouter'; import treesRouter from './routers/treesRouter'; @@ -67,7 +68,7 @@ app.use('/planters', plantersRouter); app.use('/organizations', organizationsRouter); app.use('/v2/organizations', organizationsRouterV2); app.use('/species', speciesRouter); -app.use('/v2/species', speciesRouter); +app.use('/v2/species', speciesRouterV2); app.use('/wallets', walletsRouter); app.use('/v2/wallets', walletsRouter); app.use('/transactions', transactionsRouter); diff --git a/server/infra/database/SpeciesRepositoryV2.ts b/server/infra/database/SpeciesRepositoryV2.ts new file mode 100644 index 00000000..0dbf7090 --- /dev/null +++ b/server/infra/database/SpeciesRepositoryV2.ts @@ -0,0 +1,122 @@ +import FilterOptions from 'interfaces/FilterOptions'; +import Species from 'interfaces/Species'; +import BaseRepository from './BaseRepository'; +import Session from './Session'; + +export default class SpeciesRepositoryV2 extends BaseRepository { + constructor(session: Session) { + super('tree_species', session); + } + + async getByOrganization(organization_id: number, options: FilterOptions) { + const { limit, offset } = options; + const sql = ` + SELECT + species_id as id, total, ts.name, ts.desc + FROM + ( + SELECT + ss.species_id, count(ss.species_id) as total + from webmap.species_stat ss + WHERE + ss.planter_id IN ( + SELECT + id + FROM planter p + WHERE + p.organization_id in ( SELECT entity_id from getEntityRelationshipChildren(${organization_id})) + ) + OR + ss.planting_organization_id = ${organization_id} + GROUP BY ss.species_id + ) s_count + JOIN tree_species ts + ON ts.id = s_count.species_id + ORDER BY total DESC + LIMIT ${limit} + OFFSET ${offset} + `; + const object = await this.session.getDB().raw(sql); + return object.rows; + } + +async getByPlanter(planter_id: number, options: FilterOptions) { + const { limit, offset } = options; + const sql = ` + SELECT + species_id as id, total, ts.name, ts.desc + FROM + ( + SELECT + ss.species_id, count(ss.species_id) as total + from webmap.species_stat ss + WHERE + ss.planter_id = ${planter_id} + GROUP BY ss.species_id + ) s_count + JOIN tree_species ts + ON ts.id = s_count.species_id + ORDER BY total DESC + LIMIT ${limit} + OFFSET ${offset} + `; + const object = await this.session.getDB().raw(sql); + return object.rows; + } + + async getByGrower(grower_id: string, options: FilterOptions) { + const { limit, offset } = options; + const sql = ` + SELECT + species_id as id, total, ts.name, ts.desc + FROM + ( + SELECT + ss.species_id, count(ss.species_id) as total + from webmap.species_stat ss + WHERE + ss.planter_id IN ( + SELECT + id + FROM planter p + WHERE + p.grower_account_uuid = '${grower_id}' + ) + + GROUP BY + ss.species_id + ) s_count + JOIN tree_species ts + ON ts.id = s_count.species_id + ORDER BY total DESC + LIMIT ${limit} + OFFSET ${offset} + `; + const object = await this.session.getDB().raw(sql); + return object.rows; + } + + async getByWallet(wallet_id: string, options: FilterOptions) { + const { limit, offset } = options; + const sql = ` + SELECT + species_id as id, total, ts.name, ts.desc + FROM + ( + SELECT + ss.species_id, count(ss.species_id) as total + from webmap.species_stat ss + WHERE + ss.wallet_id::text = '${wallet_id}' + GROUP BY ss.species_id + ) s_count + JOIN tree_species ts + ON ts.id = s_count.species_id + ORDER BY total DESC + LIMIT ${limit} + OFFSET ${offset} + `; + const object = await this.session.getDB().raw(sql); + return object.rows; + } +} \ No newline at end of file diff --git a/server/models/OrganizationV2.ts b/server/models/OrganizationV2.ts index 445e5f94..c3ab7cef 100644 --- a/server/models/OrganizationV2.ts +++ b/server/models/OrganizationV2.ts @@ -19,7 +19,7 @@ function getByFilter( return trees; } if (filter.grower_id){ - log.warn('using planter filter...'); + log.warn('using grower filter...'); const trees = await organizationRepository.getByGrower( filter.grower_id, options, diff --git a/server/models/SpeciesV2.ts b/server/models/SpeciesV2.ts new file mode 100644 index 00000000..45dfc7b2 --- /dev/null +++ b/server/models/SpeciesV2.ts @@ -0,0 +1,61 @@ +import log from 'loglevel'; +import FilterOptions from 'interfaces/FilterOptions'; +import Species from 'interfaces/Species'; +import { delegateRepository } from '../infra/database/delegateRepository'; +import SpeciesRepositoryV2 from '../infra/database/SpeciesRepositoryV2'; + +type Filter = Partial<{ + planter_id: number; + organization_id: number; + wallet_id: string; + grower_id:string; +}>; + +function getByFilter( + speciesRepository: SpeciesRepositoryV2, +): (filter: Filter, options: FilterOptions) => Promise { + return async function (filter: Filter, options: FilterOptions) { + if (filter.organization_id) { + log.warn('using org filter...'); + const trees = await speciesRepository.getByOrganization( + filter.organization_id, + options, + ); + return trees; + } + if (filter.planter_id) { + log.warn('using planter filter...'); + const trees = await speciesRepository.getByPlanter( + filter.planter_id, + options, + ); + return trees; + } + + if (filter.wallet_id) { + log.warn('using wallet filter...'); + const trees = await speciesRepository.getByWallet( + filter.wallet_id, + options, + ); + return trees; + } + if (filter.grower_id) { + log.warn('using grower filter...'); + const trees = await speciesRepository.getByGrower( + filter.grower_id, + options, + ); + return trees; + } + + const trees = await speciesRepository.getByFilter(filter, options); + return trees; + }; +} + +export default { + getById: delegateRepository('getById'), + getByGrower:delegateRepository('getByGrower'), + getByFilter, +}; diff --git a/server/routers/organizationsRouterV2.ts b/server/routers/organizationsRouterV2.ts index f813a774..dd7cd955 100644 --- a/server/routers/organizationsRouterV2.ts +++ b/server/routers/organizationsRouterV2.ts @@ -51,7 +51,7 @@ router.get( req.query, Joi.object().keys({ planter_id: Joi.number().integer().min(0), - grower_id:Joi.string(), + grower_id:Joi.string().guid(), limit: Joi.number().integer().min(1).max(1000), offset: Joi.number().integer().min(0), }), diff --git a/server/routers/speciesRouterV2.ts b/server/routers/speciesRouterV2.ts new file mode 100644 index 00000000..faa2ea6d --- /dev/null +++ b/server/routers/speciesRouterV2.ts @@ -0,0 +1,78 @@ +import express from 'express'; +import Joi from 'joi'; +import log from 'loglevel'; +import { handlerWrapper } from './utils'; +import Session from '../infra/database/Session'; +import SpeciesRepositoryV2 from '../infra/database/SpeciesRepositoryV2'; +import SpeciesModel from '../models/SpeciesV2'; + +const router = express.Router(); +type Filter = Partial<{ + planter_id: number; + organization_id: number; + wallet_id: string; + grower_id: string; +}>; + +router.get( + '/:id', + handlerWrapper(async (req, res) => { + Joi.assert(req.params.id, Joi.number().required()); + const repo = new SpeciesRepositoryV2(new Session()); + const exe = SpeciesModel.getById(repo); + const result = await exe(req.params.id); + res.send(result); + res.end(); + }), +); + +router.get( + '/', + handlerWrapper(async (req, res) => { + Joi.assert( + req.query, + Joi.object().keys({ + organization_id: Joi.number().integer().min(0), + planter_id: Joi.number().integer().min(0), + grower_id:Joi.string().guid(), + wallet_id: Joi.string(), + limit: Joi.number().integer().min(1).max(1000), + offset: Joi.number().integer().min(0), + }), + ); + const { + limit = 20, + offset = 0, + planter_id, + organization_id, + wallet_id, + grower_id, + } = req.query; + const repo = new SpeciesRepositoryV2(new Session()); + const filter: Filter = {}; + if (organization_id) { + filter.organization_id = organization_id; + } else if (planter_id) { + filter.planter_id = planter_id; + } else if (wallet_id) { + filter.wallet_id = wallet_id; + } else if(grower_id){ + filter.grower_id = grower_id; + } + const begin = Date.now(); + const result = await SpeciesModel.getByFilter(repo)(filter, { + limit, + offset, + }); + log.warn('species filter:', filter, 'took time:', Date.now() - begin, 'ms'); + res.send({ + total: null, + offset, + limit, + species: result, + }); + res.end(); + }), +); + +export default router; From 1ee67678879c8af6aea20fccd09c391b959f7d4f Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Mon, 17 Jul 2023 16:37:00 +0530 Subject: [PATCH 42/65] fix:species total counter --- server/infra/database/SpeciesRepository.ts | 29 ++++++++++++++++ server/infra/database/SpeciesRepositoryV2.ts | 33 ++++++++++++++++-- server/models/Species.ts | 17 ++++++++++ server/models/SpeciesV2.ts | 35 ++++++++++++++------ server/routers/speciesRouter.ts | 2 +- server/routers/speciesRouterV2.ts | 10 +++--- 6 files changed, 108 insertions(+), 18 deletions(-) diff --git a/server/infra/database/SpeciesRepository.ts b/server/infra/database/SpeciesRepository.ts index 331341af..ce75b0ce 100644 --- a/server/infra/database/SpeciesRepository.ts +++ b/server/infra/database/SpeciesRepository.ts @@ -40,6 +40,35 @@ export default class SpeciesRepository extends BaseRepository { return object.rows; } + async countByOrganization(organization_id: number) { + const totalSql = ` + SELECT + species_id as id, total, ts.name, ts.desc + FROM + ( + SELECT + ss.species_id, count(ss.species_id) as total + from webmap.species_stat ss + WHERE + ss.planter_id IN ( + SELECT + id + FROM planter p + WHERE + p.organization_id in ( SELECT entity_id from getEntityRelationshipChildren(${organization_id})) + ) + OR + ss.planting_organization_id = ${organization_id} + GROUP BY ss.species_id + ) s_count + JOIN tree_species ts + ON ts.id = s_count.species_id + ORDER BY total DESC + `; + const total = await this.session.getDB().raw(totalSql); + return parseInt(total.rows[0].count.toString()); + } + async getByPlanter(planter_id: number, options: FilterOptions) { const { limit, offset } = options; const sql = ` diff --git a/server/infra/database/SpeciesRepositoryV2.ts b/server/infra/database/SpeciesRepositoryV2.ts index 0dbf7090..b4dcb321 100644 --- a/server/infra/database/SpeciesRepositoryV2.ts +++ b/server/infra/database/SpeciesRepositoryV2.ts @@ -40,7 +40,36 @@ export default class SpeciesRepositoryV2 extends BaseRepository { return object.rows; } -async getByPlanter(planter_id: number, options: FilterOptions) { + async countByOrganization(organization_id: number) { + const totalSql = ` + SELECT + species_id as id, total, ts.name, ts.desc + FROM + ( + SELECT + ss.species_id, count(ss.species_id) as total + from webmap.species_stat ss + WHERE + ss.planter_id IN ( + SELECT + id + FROM planter p + WHERE + p.organization_id in ( SELECT entity_id from getEntityRelationshipChildren(${organization_id})) + ) + OR + ss.planting_organization_id = ${organization_id} + GROUP BY ss.species_id + ) s_count + JOIN tree_species ts + ON ts.id = s_count.species_id + ORDER BY total DESC + `; + const total = await this.session.getDB().raw(totalSql); + return parseInt(total.rows[0].count.toString()); + } + + async getByPlanter(planter_id: number, options: FilterOptions) { const { limit, offset } = options; const sql = ` SELECT @@ -119,4 +148,4 @@ async getByPlanter(planter_id: number, options: FilterOptions) { const object = await this.session.getDB().raw(sql); return object.rows; } -} \ No newline at end of file +} diff --git a/server/models/Species.ts b/server/models/Species.ts index cb73ae83..195465fd 100644 --- a/server/models/Species.ts +++ b/server/models/Species.ts @@ -45,7 +45,24 @@ function getByFilter( }; } +function countByFilter( + speciesRepository: SpeciesRepository, +): (filter: Filter) => Promise { + return async function (filter: Filter) { + if (filter.organization_id) { + log.warn('using org filter...'); + const total = await speciesRepository.countByOrganization( + filter.organization_id, + ); + return total; + } + const total = await speciesRepository.countByFilter(filter); + return total; + }; +} + export default { getById: delegateRepository('getById'), getByFilter, + countByFilter, }; diff --git a/server/models/SpeciesV2.ts b/server/models/SpeciesV2.ts index 45dfc7b2..4ec0a13b 100644 --- a/server/models/SpeciesV2.ts +++ b/server/models/SpeciesV2.ts @@ -8,7 +8,7 @@ type Filter = Partial<{ planter_id: number; organization_id: number; wallet_id: string; - grower_id:string; + grower_id: string; }>; function getByFilter( @@ -41,21 +41,36 @@ function getByFilter( return trees; } if (filter.grower_id) { - log.warn('using grower filter...'); - const trees = await speciesRepository.getByGrower( - filter.grower_id, - options, - ); - return trees; - } + log.warn('using grower filter...'); + const trees = await speciesRepository.getByGrower( + filter.grower_id, + options, + ); + return trees; + } const trees = await speciesRepository.getByFilter(filter, options); return trees; }; } - +function countByFilter( + speciesRepository: SpeciesRepositoryV2, +): (filter: Filter) => Promise { + return async function (filter: Filter) { + if (filter.organization_id) { + log.warn('using org filter...'); + const total = await speciesRepository.countByOrganization( + filter.organization_id, + ); + return total; + } + const total = await speciesRepository.countByFilter(filter); + return total; + }; +} export default { getById: delegateRepository('getById'), - getByGrower:delegateRepository('getByGrower'), + getByGrower: delegateRepository('getByGrower'), getByFilter, + countByFilter, }; diff --git a/server/routers/speciesRouter.ts b/server/routers/speciesRouter.ts index 4c66a131..5682785b 100644 --- a/server/routers/speciesRouter.ts +++ b/server/routers/speciesRouter.ts @@ -61,7 +61,7 @@ router.get( }); log.warn('species filter:', filter, 'took time:', Date.now() - begin, 'ms'); res.send({ - total: null, + total: await SpeciesModel.countByFilter(repo)(filter), offset, limit, species: result, diff --git a/server/routers/speciesRouterV2.ts b/server/routers/speciesRouterV2.ts index faa2ea6d..3ee160a0 100644 --- a/server/routers/speciesRouterV2.ts +++ b/server/routers/speciesRouterV2.ts @@ -34,7 +34,7 @@ router.get( Joi.object().keys({ organization_id: Joi.number().integer().min(0), planter_id: Joi.number().integer().min(0), - grower_id:Joi.string().guid(), + grower_id: Joi.string().guid(), wallet_id: Joi.string(), limit: Joi.number().integer().min(1).max(1000), offset: Joi.number().integer().min(0), @@ -56,9 +56,9 @@ router.get( filter.planter_id = planter_id; } else if (wallet_id) { filter.wallet_id = wallet_id; - } else if(grower_id){ - filter.grower_id = grower_id; - } + } else if (grower_id) { + filter.grower_id = grower_id; + } const begin = Date.now(); const result = await SpeciesModel.getByFilter(repo)(filter, { limit, @@ -66,7 +66,7 @@ router.get( }); log.warn('species filter:', filter, 'took time:', Date.now() - begin, 'ms'); res.send({ - total: null, + total: await SpeciesModel.countByFilter(repo)(filter), offset, limit, species: result, From 50432797232dfe4782b78912839dba85266bb79d Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Mon, 17 Jul 2023 17:02:39 +0530 Subject: [PATCH 43/65] fix:organization total counter --- server/models/Organization.ts | 10 ++++++++++ server/models/OrganizationV2.ts | 10 +++++++++- server/routers/organizationsRouter.ts | 2 +- server/routers/organizationsRouterV2.ts | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/server/models/Organization.ts b/server/models/Organization.ts index d011c297..f13d89cb 100644 --- a/server/models/Organization.ts +++ b/server/models/Organization.ts @@ -33,6 +33,15 @@ function getOrganizationLinks(organization) { return links; } +function countByFilter( + organizationRepository: OrganizationRepository, +): (filter: Filter) => Promise { + return async function (filter: Filter) { + const total = await organizationRepository.countByFilter(filter); + return total; + }; +} + export default { getById: delegateRepository('getById'), getByMapName: delegateRepository( @@ -40,6 +49,7 @@ export default { ), getByFilter, getOrganizationLinks, + countByFilter, getFeaturedOrganizations: delegateRepository< OrganizationRepository, Organization diff --git a/server/models/OrganizationV2.ts b/server/models/OrganizationV2.ts index c3ab7cef..3d5ecdbb 100644 --- a/server/models/OrganizationV2.ts +++ b/server/models/OrganizationV2.ts @@ -39,13 +39,21 @@ function getOrganizationLinks(organization) { }; return links; } - +function countByFilter( + organizationRepository: OrganizationRepositoryV2, +): (filter: Filter) => Promise { + return async function (filter: Filter) { + const total = await organizationRepository.countByFilter(filter); + return total; + }; +} export default { getById: delegateRepository('getById'), getByMapName: delegateRepository( 'getByMapName', ), getByFilter, + countByFilter, getOrganizationLinks, getFeaturedOrganizations: delegateRepository< OrganizationRepositoryV2, diff --git a/server/routers/organizationsRouter.ts b/server/routers/organizationsRouter.ts index a20eb608..b05fa4c5 100644 --- a/server/routers/organizationsRouter.ts +++ b/server/routers/organizationsRouter.ts @@ -66,7 +66,7 @@ router.get( offset, }); res.send({ - total: null, + total: await OrganizationModel.countByFilter(repo)(filter), offset, limit, organizations: result.map((organization) => ({ diff --git a/server/routers/organizationsRouterV2.ts b/server/routers/organizationsRouterV2.ts index dd7cd955..b616d154 100644 --- a/server/routers/organizationsRouterV2.ts +++ b/server/routers/organizationsRouterV2.ts @@ -69,7 +69,7 @@ router.get( offset, }); res.send({ - total: null, + total: await OrganizationModel.countByFilter(repo)(filter), offset, limit, organizations: result.map((organization) => ({ From 4ea7d2cd55a6565f72acc22ebba3f10d25275869 Mon Sep 17 00:00:00 2001 From: Dadiorchen Date: Wed, 19 Jul 2023 16:41:34 +0800 Subject: [PATCH 44/65] feat: trees/uuid --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e273998b..666d54fe 100644 --- a/README.md +++ b/README.md @@ -143,3 +143,4 @@ DATABASE_URL=[the link provided] NODE_TLS_REJECT_UNAUTHORIZED='0' npm run test-e . . . +. From 4db26f2b6a3df2fce5387c228f837b5401130308 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 19 Jul 2023 08:42:53 +0000 Subject: [PATCH 45/65] chore(release): 1.70.0 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 843560f6..d2c59fd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# [1.70.0](https://github.com/Greenstand/treetracker-query-api/compare/v1.69.2...v1.70.0) (2023-07-19) + +### Features + +- trees/uuid ([4ea7d2c](https://github.com/Greenstand/treetracker-query-api/commit/4ea7d2cd55a6565f72acc22ebba3f10d25275869)) + ## [1.69.2](https://github.com/Greenstand/treetracker-query-api/compare/v1.69.1...v1.69.2) (2023-07-04) ### Bug Fixes diff --git a/package.json b/package.json index 04d0223b..d3a7c7a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.69.2", + "version": "1.70.0", "private": false, "keywords": [ "ecology" From b06eda9704f09f71d427a6811a4ea18a1dca7c61 Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Sun, 23 Jul 2023 12:48:35 +0530 Subject: [PATCH 46/65] fix:organization_counter for species --- server/infra/database/SpeciesRepository.ts | 43 +++++++++++----------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/server/infra/database/SpeciesRepository.ts b/server/infra/database/SpeciesRepository.ts index ce75b0ce..3bc8ec67 100644 --- a/server/infra/database/SpeciesRepository.ts +++ b/server/infra/database/SpeciesRepository.ts @@ -43,30 +43,31 @@ export default class SpeciesRepository extends BaseRepository { async countByOrganization(organization_id: number) { const totalSql = ` SELECT - species_id as id, total, ts.name, ts.desc - FROM - ( - SELECT - ss.species_id, count(ss.species_id) as total - from webmap.species_stat ss - WHERE - ss.planter_id IN ( - SELECT - id - FROM planter p + species_id as id, total, ts.name, ts.desc + FROM + ( + SELECT + ss.species_id, count(ss.species_id) as total + from webmap.species_stat ss WHERE - p.organization_id in ( SELECT entity_id from getEntityRelationshipChildren(${organization_id})) - ) - OR - ss.planting_organization_id = ${organization_id} - GROUP BY ss.species_id - ) s_count - JOIN tree_species ts - ON ts.id = s_count.species_id - ORDER BY total DESC + ss.planter_id IN ( + SELECT + id + FROM planter p + WHERE + p.organization_id in ( SELECT entity_id from getEntityRelationshipChildren(${organization_id})) + ) + OR + ss.planting_organization_id = ${organization_id} + GROUP BY ss.species_id + ) s_count + JOIN tree_species ts + ON ts.id = s_count.species_id + ORDER BY total DESC + `; const total = await this.session.getDB().raw(totalSql); - return parseInt(total.rows[0].count.toString()); + return parseInt(total.rows.length); } async getByPlanter(planter_id: number, options: FilterOptions) { From 9e52d0c8c27256163b833ebb2e559a9afea29867 Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Sun, 23 Jul 2023 12:57:49 +0530 Subject: [PATCH 47/65] fix:organization_counter for speciesV2 --- server/infra/database/SpeciesRepositoryV2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/infra/database/SpeciesRepositoryV2.ts b/server/infra/database/SpeciesRepositoryV2.ts index b4dcb321..19746451 100644 --- a/server/infra/database/SpeciesRepositoryV2.ts +++ b/server/infra/database/SpeciesRepositoryV2.ts @@ -66,7 +66,7 @@ export default class SpeciesRepositoryV2 extends BaseRepository { ORDER BY total DESC `; const total = await this.session.getDB().raw(totalSql); - return parseInt(total.rows[0].count.toString()); + return parseInt(total.rows.length); } async getByPlanter(planter_id: number, options: FilterOptions) { From 513eba62edc246713175e6298f74f48fe90dc7a8 Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Mon, 24 Jul 2023 23:04:42 +0530 Subject: [PATCH 48/65] fix:organization_filter for growerV2 --- server/infra/database/GrowerAccountRepository.ts | 4 +--- server/routers/growerAccountsRouter.ts | 4 ++-- server/routers/utils.ts | 5 ++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/server/infra/database/GrowerAccountRepository.ts b/server/infra/database/GrowerAccountRepository.ts index ef404a49..68f7ed2a 100644 --- a/server/infra/database/GrowerAccountRepository.ts +++ b/server/infra/database/GrowerAccountRepository.ts @@ -100,9 +100,7 @@ export default class GrowerAccountRepository extends BaseRepository Date: Mon, 31 Jul 2023 09:12:07 +0000 Subject: [PATCH 50/65] chore(release): 1.70.1 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2c59fd8..830d2bd1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.70.1](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.0...v1.70.1) (2023-07-31) + +### Bug Fixes + +- trigger deployment ([4f6e363](https://github.com/Greenstand/treetracker-query-api/commit/4f6e363bc6419f3e4afcad368d289a80af1b07a2)) + # [1.70.0](https://github.com/Greenstand/treetracker-query-api/compare/v1.69.2...v1.70.0) (2023-07-19) ### Features diff --git a/package.json b/package.json index d3a7c7a1..78b4f0a4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.70.0", + "version": "1.70.1", "private": false, "keywords": [ "ecology" From 32df39a98cd8673d71602bbb8c4471c38ec53ba6 Mon Sep 17 00:00:00 2001 From: deanchen Date: Wed, 16 Aug 2023 17:04:37 +0800 Subject: [PATCH 51/65] fix: bug with total by a commit Revert "fix:organization total counter" This reverts commit 50432797232dfe4782b78912839dba85266bb79d. --- server/models/Organization.ts | 10 ---------- server/models/OrganizationV2.ts | 10 +--------- server/routers/organizationsRouter.ts | 2 +- server/routers/organizationsRouterV2.ts | 2 +- 4 files changed, 3 insertions(+), 21 deletions(-) diff --git a/server/models/Organization.ts b/server/models/Organization.ts index f13d89cb..d011c297 100644 --- a/server/models/Organization.ts +++ b/server/models/Organization.ts @@ -33,15 +33,6 @@ function getOrganizationLinks(organization) { return links; } -function countByFilter( - organizationRepository: OrganizationRepository, -): (filter: Filter) => Promise { - return async function (filter: Filter) { - const total = await organizationRepository.countByFilter(filter); - return total; - }; -} - export default { getById: delegateRepository('getById'), getByMapName: delegateRepository( @@ -49,7 +40,6 @@ export default { ), getByFilter, getOrganizationLinks, - countByFilter, getFeaturedOrganizations: delegateRepository< OrganizationRepository, Organization diff --git a/server/models/OrganizationV2.ts b/server/models/OrganizationV2.ts index 3d5ecdbb..c3ab7cef 100644 --- a/server/models/OrganizationV2.ts +++ b/server/models/OrganizationV2.ts @@ -39,21 +39,13 @@ function getOrganizationLinks(organization) { }; return links; } -function countByFilter( - organizationRepository: OrganizationRepositoryV2, -): (filter: Filter) => Promise { - return async function (filter: Filter) { - const total = await organizationRepository.countByFilter(filter); - return total; - }; -} + export default { getById: delegateRepository('getById'), getByMapName: delegateRepository( 'getByMapName', ), getByFilter, - countByFilter, getOrganizationLinks, getFeaturedOrganizations: delegateRepository< OrganizationRepositoryV2, diff --git a/server/routers/organizationsRouter.ts b/server/routers/organizationsRouter.ts index b05fa4c5..a20eb608 100644 --- a/server/routers/organizationsRouter.ts +++ b/server/routers/organizationsRouter.ts @@ -66,7 +66,7 @@ router.get( offset, }); res.send({ - total: await OrganizationModel.countByFilter(repo)(filter), + total: null, offset, limit, organizations: result.map((organization) => ({ diff --git a/server/routers/organizationsRouterV2.ts b/server/routers/organizationsRouterV2.ts index b616d154..dd7cd955 100644 --- a/server/routers/organizationsRouterV2.ts +++ b/server/routers/organizationsRouterV2.ts @@ -69,7 +69,7 @@ router.get( offset, }); res.send({ - total: await OrganizationModel.countByFilter(repo)(filter), + total: null, offset, limit, organizations: result.map((organization) => ({ From 297a16abc3d4cc4ca848cd6a8dc41d125df30198 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 16 Aug 2023 09:12:48 +0000 Subject: [PATCH 52/65] chore(release): 1.70.2 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 830d2bd1..3ada6fdd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.70.2](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.1...v1.70.2) (2023-08-16) + +### Bug Fixes + +- bug with total by a commit ([32df39a](https://github.com/Greenstand/treetracker-query-api/commit/32df39a98cd8673d71602bbb8c4471c38ec53ba6)) + ## [1.70.1](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.0...v1.70.1) (2023-07-31) ### Bug Fixes diff --git a/package.json b/package.json index 78b4f0a4..779ccd7e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.70.1", + "version": "1.70.2", "private": false, "keywords": [ "ecology" From 70a64abd2995806fc50f3fa494d079d265a7323d Mon Sep 17 00:00:00 2001 From: deanchen Date: Wed, 16 Aug 2023 17:28:23 +0800 Subject: [PATCH 53/65] fix: species total bug --- server/routers/speciesRouter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/speciesRouter.ts b/server/routers/speciesRouter.ts index 5682785b..4c66a131 100644 --- a/server/routers/speciesRouter.ts +++ b/server/routers/speciesRouter.ts @@ -61,7 +61,7 @@ router.get( }); log.warn('species filter:', filter, 'took time:', Date.now() - begin, 'ms'); res.send({ - total: await SpeciesModel.countByFilter(repo)(filter), + total: null, offset, limit, species: result, From 3f22b2f739ea1026c5103d1792f87ffbc33efd77 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 16 Aug 2023 09:30:15 +0000 Subject: [PATCH 54/65] chore(release): 1.70.3 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ada6fdd..e43beabc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.70.3](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.2...v1.70.3) (2023-08-16) + +### Bug Fixes + +- species total bug ([70a64ab](https://github.com/Greenstand/treetracker-query-api/commit/70a64abd2995806fc50f3fa494d079d265a7323d)) + ## [1.70.2](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.1...v1.70.2) (2023-08-16) ### Bug Fixes diff --git a/package.json b/package.json index 779ccd7e..c814e5e8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.70.2", + "version": "1.70.3", "private": false, "keywords": [ "ecology" From 9bafbf6f3b8691f56fd0a374912444394cfb0d2a Mon Sep 17 00:00:00 2001 From: weiyu Date: Fri, 15 Sep 2023 14:32:15 -0500 Subject: [PATCH 55/65] fix: do not display inactive trees, and throw 404 error --- server/routers/treesRouter.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/server/routers/treesRouter.ts b/server/routers/treesRouter.ts index 9de19399..efb09bef 100644 --- a/server/routers/treesRouter.ts +++ b/server/routers/treesRouter.ts @@ -1,11 +1,11 @@ import express from 'express'; import Joi from 'joi'; import FilterOptions from 'interfaces/FilterOptions'; -import Tree from 'interfaces/Tree'; import { handlerWrapper } from './utils'; import Session from '../infra/database/Session'; import TreeRepository from '../infra/database/TreeRepository'; import TreeModel from '../models/Tree'; +import HttpError from '../utils/HttpError'; const router = express.Router(); type Filter = Partial<{ @@ -34,22 +34,26 @@ router.get( '/:val', handlerWrapper(async (req, res) => { const repo = new TreeRepository(new Session()); - let result - if(isNaN(Number(req.params.val))){ + let result; + if (isNaN(Number(req.params.val))) { Joi.assert(req.params.val, Joi.string().guid().required()); const exe = TreeModel.getByUUID(repo); - result = await exe(req.params.val); - } else{ + result = await exe(req.params.val); + } else { Joi.assert(req.params.val, Joi.number().required()); const exe = TreeModel.getById(repo); result = await exe(req.params.val); } + + if (result.active === false) { + throw new HttpError(404, `Can not find trees by id:${result.id}`); + } + res.send(result); res.end(); }), ); - router.get( '/', handlerWrapper(async (req, res) => { From 9ec872fa974170d07d15983c98243dc76845b691 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 16 Sep 2023 03:01:13 +0000 Subject: [PATCH 56/65] chore(release): 1.70.4 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e43beabc..221e443c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.70.4](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.3...v1.70.4) (2023-09-16) + +### Bug Fixes + +- do not display inactive trees, and throw 404 error ([9bafbf6](https://github.com/Greenstand/treetracker-query-api/commit/9bafbf6f3b8691f56fd0a374912444394cfb0d2a)) + ## [1.70.3](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.2...v1.70.3) (2023-08-16) ### Bug Fixes diff --git a/package.json b/package.json index c814e5e8..27ff0f49 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.70.3", + "version": "1.70.4", "private": false, "keywords": [ "ecology" From 788343072c25ae8a0d0936ffbbba3cea0b911128 Mon Sep 17 00:00:00 2001 From: aayushgauba <55630226+aayushgauba@users.noreply.github.com> Date: Fri, 22 Sep 2023 13:50:12 +0530 Subject: [PATCH 57/65] fix: species v2 --- server/infra/database/SpeciesRepositoryV2.ts | 221 ++++++++----------- server/interfaces/SpeciesFilter.ts | 16 ++ server/models/SpeciesV2.ts | 61 +---- server/routers/speciesRouterV2.ts | 17 +- 4 files changed, 119 insertions(+), 196 deletions(-) create mode 100644 server/interfaces/SpeciesFilter.ts diff --git a/server/infra/database/SpeciesRepositoryV2.ts b/server/infra/database/SpeciesRepositoryV2.ts index 19746451..26ef19de 100644 --- a/server/infra/database/SpeciesRepositoryV2.ts +++ b/server/infra/database/SpeciesRepositoryV2.ts @@ -6,146 +6,99 @@ import Session from './Session'; export default class SpeciesRepositoryV2 extends BaseRepository { constructor(session: Session) { super('tree_species', session); + this.tableName = 'herbarium.species'; } - async getByOrganization(organization_id: number, options: FilterOptions) { - const { limit, offset } = options; - const sql = ` - SELECT - species_id as id, total, ts.name, ts.desc - FROM - ( - SELECT - ss.species_id, count(ss.species_id) as total - from webmap.species_stat ss - WHERE - ss.planter_id IN ( - SELECT - id - FROM planter p - WHERE - p.organization_id in ( SELECT entity_id from getEntityRelationshipChildren(${organization_id})) - ) - OR - ss.planting_organization_id = ${organization_id} - GROUP BY ss.species_id - ) s_count - JOIN tree_species ts - ON ts.id = s_count.species_id - ORDER BY total DESC - LIMIT ${limit} - OFFSET ${offset} - `; - const object = await this.session.getDB().raw(sql); - return object.rows; - } + filterWhereBuilder(object, builder) { + const result = builder; + const { + whereNulls = [], + whereNotNulls = [], + whereIns = [], + ...parameters + } = object; - async countByOrganization(organization_id: number) { - const totalSql = ` - SELECT - species_id as id, total, ts.name, ts.desc - FROM - ( - SELECT - ss.species_id, count(ss.species_id) as total - from webmap.species_stat ss - WHERE - ss.planter_id IN ( - SELECT - id - FROM planter p - WHERE - p.organization_id in ( SELECT entity_id from getEntityRelationshipChildren(${organization_id})) - ) - OR - ss.planting_organization_id = ${organization_id} - GROUP BY ss.species_id - ) s_count - JOIN tree_species ts - ON ts.id = s_count.species_id - ORDER BY total DESC - `; - const total = await this.session.getDB().raw(totalSql); - return parseInt(total.rows.length); - } + result.whereNot(`${this.tableName}.status`, 'deleted'); + whereNotNulls.forEach((whereNot) => { + result.whereNotNull(whereNot); + }); - async getByPlanter(planter_id: number, options: FilterOptions) { - const { limit, offset } = options; - const sql = ` - SELECT - species_id as id, total, ts.name, ts.desc - FROM - ( - SELECT - ss.species_id, count(ss.species_id) as total - from webmap.species_stat ss - WHERE - ss.planter_id = ${planter_id} - GROUP BY ss.species_id - ) s_count - JOIN tree_species ts - ON ts.id = s_count.species_id - ORDER BY total DESC - LIMIT ${limit} - OFFSET ${offset} - `; - const object = await this.session.getDB().raw(sql); - return object.rows; - } + whereNulls.forEach((whereNull) => { + result.whereNull(whereNull); + }); - async getByGrower(grower_id: string, options: FilterOptions) { - const { limit, offset } = options; - const sql = ` - SELECT - species_id as id, total, ts.name, ts.desc - FROM - ( - SELECT - ss.species_id, count(ss.species_id) as total - from webmap.species_stat ss - WHERE - ss.planter_id IN ( - SELECT - id - FROM planter p - WHERE - p.grower_account_uuid = '${grower_id}' - ) + whereIns.forEach((whereIn) => { + result.whereIn(whereIn.field, whereIn.values); + }); - GROUP BY - ss.species_id - ) s_count - JOIN tree_species ts - ON ts.id = s_count.species_id - ORDER BY total DESC - LIMIT ${limit} - OFFSET ${offset} - `; - const object = await this.session.getDB().raw(sql); - return object.rows; - } + const filterObject = { ...parameters }; + + if (filterObject.id) { + result.where(`${this.tableName}.id`, '=', filterObject.id); + delete filterObject.id; + } + + if (filterObject.scientific_name) { + result.where( + `${this.tableName}.scientific_name`, + 'ilike', + `%${filterObject.scientific_name}%`, + ); + delete filterObject.scientific_name; + } + + if (filterObject.organization_id) { + result.where( + `${this.tableName}.organization_id`, + '=', + `${filterObject.organization_id}`, + ); + delete filterObject.organization_id; + } + + // if 'captures_amount_max' === 0, 'captures_amount_min' can be only 0. + if (filterObject.captures_amount_max === 0) { + result.whereNull('c.captures_count'); + delete filterObject.captures_amount_min; + delete filterObject.captures_amount_max; + } + + // if 'captures_amount_max' === 0 and 'captures_amount_max' is not defined, all results should be returned. + if ( + filterObject.captures_amount_min === 0 && + !filterObject.captures_amount_max + ) { + delete filterObject.captures_amount_min; + delete filterObject.captures_amount_max; + } + + if (filterObject.captures_amount_min) { + result.where( + `c.captures_count`, + '>=', + `${filterObject.captures_amount_min}`, + ); + delete filterObject.captures_amount_min; + } + + if (filterObject.captures_amount_max) { + result.where( + `c.captures_count`, + '<=', + `${filterObject.captures_amount_max}`, + ); + delete filterObject.captures_amount_max; + } + + if (filterObject.wallet) { + result.where( + `${this.tableName}.wallet`, + 'ilike', + `%${filterObject.wallet}%`, + ); + delete filterObject.wallet; + } - async getByWallet(wallet_id: string, options: FilterOptions) { - const { limit, offset } = options; - const sql = ` - SELECT - species_id as id, total, ts.name, ts.desc - FROM - ( - SELECT - ss.species_id, count(ss.species_id) as total - from webmap.species_stat ss - WHERE - ss.wallet_id::text = '${wallet_id}' - GROUP BY ss.species_id - ) s_count - JOIN tree_species ts - ON ts.id = s_count.species_id - ORDER BY total DESC - LIMIT ${limit} - OFFSET ${offset} - `; - const object = await this.session.getDB().raw(sql); - return object.rows; + result.where(filterObject); } } diff --git a/server/interfaces/SpeciesFilter.ts b/server/interfaces/SpeciesFilter.ts new file mode 100644 index 00000000..66dcebad --- /dev/null +++ b/server/interfaces/SpeciesFilter.ts @@ -0,0 +1,16 @@ +import DbModel from './DbModel'; + +interface SpeciesFilter extends DbModel { + id?: number; + scientific_name?: string; + description?: string; + limit?: number; + offset?: number; + keyword?: string; + morphology?: string; + range?: string; + created_at?: string; + updated_at?: string; +} + +export default SpeciesFilter; diff --git a/server/models/SpeciesV2.ts b/server/models/SpeciesV2.ts index 4ec0a13b..938cf804 100644 --- a/server/models/SpeciesV2.ts +++ b/server/models/SpeciesV2.ts @@ -1,76 +1,27 @@ import log from 'loglevel'; import FilterOptions from 'interfaces/FilterOptions'; import Species from 'interfaces/Species'; +import SpeciesFilter from 'interfaces/SpeciesFilter'; import { delegateRepository } from '../infra/database/delegateRepository'; import SpeciesRepositoryV2 from '../infra/database/SpeciesRepositoryV2'; type Filter = Partial<{ planter_id: number; - organization_id: number; wallet_id: string; grower_id: string; }>; function getByFilter( speciesRepository: SpeciesRepositoryV2, -): (filter: Filter, options: FilterOptions) => Promise { - return async function (filter: Filter, options: FilterOptions) { - if (filter.organization_id) { - log.warn('using org filter...'); - const trees = await speciesRepository.getByOrganization( - filter.organization_id, - options, - ); - return trees; - } - if (filter.planter_id) { - log.warn('using planter filter...'); - const trees = await speciesRepository.getByPlanter( - filter.planter_id, - options, - ); - return trees; - } - - if (filter.wallet_id) { - log.warn('using wallet filter...'); - const trees = await speciesRepository.getByWallet( - filter.wallet_id, - options, - ); - return trees; - } - if (filter.grower_id) { - log.warn('using grower filter...'); - const trees = await speciesRepository.getByGrower( - filter.grower_id, - options, - ); - return trees; - } - - const trees = await speciesRepository.getByFilter(filter, options); - return trees; - }; -} -function countByFilter( - speciesRepository: SpeciesRepositoryV2, -): (filter: Filter) => Promise { - return async function (filter: Filter) { - if (filter.organization_id) { - log.warn('using org filter...'); - const total = await speciesRepository.countByOrganization( - filter.organization_id, - ); - return total; - } - const total = await speciesRepository.countByFilter(filter); - return total; +): (filter: SpeciesFilter, options: FilterOptions) => Promise { + return async function (filter: SpeciesFilter, options: FilterOptions) { + const result = await speciesRepository.getByFilter(filter, options); + return result; }; } + export default { getById: delegateRepository('getById'), getByGrower: delegateRepository('getByGrower'), getByFilter, - countByFilter, }; diff --git a/server/routers/speciesRouterV2.ts b/server/routers/speciesRouterV2.ts index 3ee160a0..1d2e9518 100644 --- a/server/routers/speciesRouterV2.ts +++ b/server/routers/speciesRouterV2.ts @@ -9,7 +9,7 @@ import SpeciesModel from '../models/SpeciesV2'; const router = express.Router(); type Filter = Partial<{ planter_id: number; - organization_id: number; + organization_id: string; wallet_id: string; grower_id: string; }>; @@ -17,7 +17,7 @@ type Filter = Partial<{ router.get( '/:id', handlerWrapper(async (req, res) => { - Joi.assert(req.params.id, Joi.number().required()); + Joi.assert(req.params.id, Joi.string().uuid().required()); const repo = new SpeciesRepositoryV2(new Session()); const exe = SpeciesModel.getById(repo); const result = await exe(req.params.id); @@ -32,12 +32,16 @@ router.get( Joi.assert( req.query, Joi.object().keys({ - organization_id: Joi.number().integer().min(0), - planter_id: Joi.number().integer().min(0), - grower_id: Joi.string().guid(), - wallet_id: Joi.string(), limit: Joi.number().integer().min(1).max(1000), offset: Joi.number().integer().min(0), + keyword: Joi.string(), + id: Joi.string().uuid(), + scientific_name: Joi.string(), + description: Joi.string(), + morphology: Joi.string(), + range: Joi.string(), + created_at: Joi.string(), + updated_at: Joi.string(), }), ); const { @@ -66,7 +70,6 @@ router.get( }); log.warn('species filter:', filter, 'took time:', Date.now() - begin, 'ms'); res.send({ - total: await SpeciesModel.countByFilter(repo)(filter), offset, limit, species: result, From b5288ed37e7334b890a6c42a852114282fd2d017 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 27 Sep 2023 06:41:40 +0000 Subject: [PATCH 58/65] chore(release): 1.70.5 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 221e443c..b1bd01f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.70.5](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.4...v1.70.5) (2023-09-27) + +### Bug Fixes + +- species v2 ([7883430](https://github.com/Greenstand/treetracker-query-api/commit/788343072c25ae8a0d0936ffbbba3cea0b911128)) + ## [1.70.4](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.3...v1.70.4) (2023-09-16) ### Bug Fixes diff --git a/package.json b/package.json index 27ff0f49..cdbc933b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.70.4", + "version": "1.70.5", "private": false, "keywords": [ "ecology" From 6a33308ed4adf7315066dbcbf272c933e0ca08d7 Mon Sep 17 00:00:00 2001 From: crynet Date: Tue, 3 Oct 2023 22:41:14 +0300 Subject: [PATCH 59/65] fix: queryFormatter --- server/routers/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/utils.ts b/server/routers/utils.ts index 91d0300f..fcb4f172 100644 --- a/server/routers/utils.ts +++ b/server/routers/utils.ts @@ -65,7 +65,7 @@ const queryFormatter = (req) => { ...others, }; if (req.query.organization_id) { - query.organization_id = req.query.organization_id; + query.organization_id = JSON.parse(req.query.organization_id); } if (req.query.captures_amount_min) { From 0db3a502ce47bfc84172a42a7449a48a10590329 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 4 Oct 2023 10:44:27 +0000 Subject: [PATCH 60/65] chore(release): 1.70.6 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1bd01f6..6118d3a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.70.6](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.5...v1.70.6) (2023-10-04) + +### Bug Fixes + +- queryFormatter ([6a33308](https://github.com/Greenstand/treetracker-query-api/commit/6a33308ed4adf7315066dbcbf272c933e0ca08d7)) + ## [1.70.5](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.4...v1.70.5) (2023-09-27) ### Bug Fixes diff --git a/package.json b/package.json index cdbc933b..a59ca716 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.70.5", + "version": "1.70.6", "private": false, "keywords": [ "ecology" From 494e17b8d694ee0489e96bf047e38164639a2e59 Mon Sep 17 00:00:00 2001 From: Krithin Jay Pakshootra Date: Thu, 19 Oct 2023 12:30:17 +0800 Subject: [PATCH 61/65] fix: added new type allowance for organization_id --- server/infra/database/BoundsRepository.ts | 4 +++- server/interfaces/GrowerAccountFilter.ts | 2 +- server/models/Bounds.ts | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/server/infra/database/BoundsRepository.ts b/server/infra/database/BoundsRepository.ts index ecbbf9b3..af4d002a 100644 --- a/server/infra/database/BoundsRepository.ts +++ b/server/infra/database/BoundsRepository.ts @@ -47,7 +47,9 @@ export default class BoundsRepository { return BoundsRepository.convertStringToBounds(bounds); } - async filterByOrganisation(organisationId: string): Promise { + async filterByOrganisation( + organisationId: string[] | string, + ): Promise { const organisationBoundsSql = ` select ST_EXTENT(ST_GeomFromText('POINT(' || t.lon || ' ' || t.lat || ')', 4326)) as bounds diff --git a/server/interfaces/GrowerAccountFilter.ts b/server/interfaces/GrowerAccountFilter.ts index 42aabda6..a5dd0ea1 100644 --- a/server/interfaces/GrowerAccountFilter.ts +++ b/server/interfaces/GrowerAccountFilter.ts @@ -7,7 +7,7 @@ interface GrowerAccountFilter extends DbModel { limit?: number; offset?: number; keyword?: string; - organization_id?: string; + organization_id?: string[] | string; person_id?: string; device_identifier?: string; wallet?: string; diff --git a/server/models/Bounds.ts b/server/models/Bounds.ts index 051f7e3c..5ae16897 100644 --- a/server/models/Bounds.ts +++ b/server/models/Bounds.ts @@ -5,7 +5,7 @@ import Bounds from 'interfaces/Bounds'; type BoundsFilter = Partial<{ planter_id: string; wallet_id: string; - organisation_id: string; + organisation_id: string[] | string; }>; function getByFilter( From de848bda6932e433d508948dd47a590509fd10b4 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 21 Oct 2023 10:57:18 +0000 Subject: [PATCH 62/65] chore(release): 1.70.7 [skip ci] --- CHANGELOG.md | 6 ++++++ package.json | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6118d3a4..429b9c04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## [1.70.7](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.6...v1.70.7) (2023-10-21) + +### Bug Fixes + +- added new type allowance for organization_id ([494e17b](https://github.com/Greenstand/treetracker-query-api/commit/494e17b8d694ee0489e96bf047e38164639a2e59)) + ## [1.70.6](https://github.com/Greenstand/treetracker-query-api/compare/v1.70.5...v1.70.6) (2023-10-04) ### Bug Fixes diff --git a/package.json b/package.json index a59ca716..c464d588 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "treetracker-query-api", - "version": "1.70.6", + "version": "1.70.7", "private": false, "keywords": [ "ecology" From 95e3dea32f6b55fb3ce6374bd53536bea028893a Mon Sep 17 00:00:00 2001 From: Gwynn Dandridge-Perry Date: Wed, 19 Apr 2023 08:43:58 -0700 Subject: [PATCH 63/65] feat: add contract query --- server/app.ts | 2 + server/infra/database/ContractRepository.ts | 198 ++++++++++++++++++++ server/interfaces/Contract.ts | 14 ++ server/interfaces/ContractFilter.ts | 27 +++ server/models/Contract.ts | 29 +++ server/routers/contractsRouter.ts | 132 +++++++++++++ 6 files changed, 402 insertions(+) create mode 100644 server/infra/database/ContractRepository.ts create mode 100644 server/interfaces/Contract.ts create mode 100644 server/interfaces/ContractFilter.ts create mode 100644 server/models/Contract.ts create mode 100644 server/routers/contractsRouter.ts diff --git a/server/app.ts b/server/app.ts index efbd18ba..b8ef64c3 100644 --- a/server/app.ts +++ b/server/app.ts @@ -5,6 +5,7 @@ import responseTime from 'response-time'; import organizationsRouterV2 from 'routers/organizationsRouterV2'; import boundsRouter from './routers/boundsRouter'; import capturesRouter from './routers/capturesRouter'; +import contractsRouter from './routers/contractsRouter'; import countriesRouter from './routers/countriesRouter'; import gisRouter from './routers/gisRouter'; import growerAccountsRouter from './routers/growerAccountsRouter'; @@ -80,6 +81,7 @@ app.use('/v2/growers', growerAccountsRouter); app.use('/v2/trees', treesRouterV2); app.use('/bounds', boundsRouter); app.use('/gis', gisRouter); +app.use('/contract', contractsRouter); // Global error handler app.use(errorHandler); diff --git a/server/infra/database/ContractRepository.ts b/server/infra/database/ContractRepository.ts new file mode 100644 index 00000000..649a4c25 --- /dev/null +++ b/server/infra/database/ContractRepository.ts @@ -0,0 +1,198 @@ +import Contract from 'interfaces/Contract'; +import ContractFilter from 'interfaces/ContractFilter'; +import FilterOptions from 'interfaces/FilterOptions'; +import HttpError from 'utils/HttpError'; +import BaseRepository from './BaseRepository'; +import Session from './Session'; + +export default class ContractRepository extends BaseRepository { + constructor(session: Session) { + super('contract', session); + this.tableName = 'contracts.contract'; + } + + filterWhereBuilder(object, builder) { + const result = builder; + const { + whereNulls = [], + whereNotNulls = [], + whereIns = [], + ...parameters + } = object; + + if (parameters.tokenized === 'true') { + whereNotNulls.push('wallet.token.id'); + } else if (parameters.tokenized === 'false') { + whereNulls.push('wallet.token.id'); + } + delete parameters.tokenized; + + // result.whereNot(`${this.tableName}.status`, 'deleted'); + + whereNotNulls.forEach((whereNot) => { + // to map table names to fields for query + switch (true) { + case whereNot === 'tag_id': + result.whereNotNull('treetracker.capture_tag.tag_id'); + break; + default: + result.whereNotNull(whereNot); + } + + // result.whereNotNull(whereNot); + }); + + whereNulls.forEach((whereNull) => { + // to map table names to fields for query + switch (true) { + case whereNull === 'tag_id': + result.whereNull('treetracker.capture_tag.tag_id'); + break; + default: + result.whereNull(whereNull); + } + // result.whereNull(whereNull); + }); + + whereIns.forEach((whereIn) => { + result.whereIn(whereIn.field, whereIn.values); + }); + + const filterObject = { ...parameters }; + + if (filterObject.startDate) { + result.where( + `${this.tableName}.captured_at`, + '>=', + filterObject.startDate, + ); + delete filterObject.startDate; + } + if (filterObject.endDate) { + result.where(`${this.tableName}.captured_at`, '<=', filterObject.endDate); + delete filterObject.endDate; + } + + // if (filterObject.tag_id) { + // filterObject[`treetracker.capture_tag.tag_id`] = filterObject.tag_id; + // delete filterObject.tag_id; + // } + + if (filterObject.id) { + result.where(`${this.tableName}.id`, '=', filterObject.id); + delete filterObject.id; + } + + // if (filterObject.reference_id) { + // result.where( + // `${this.tableName}.reference_id`, + // '=', + // filterObject.reference_id, + // ); + // delete filterObject.reference_id; + // } + + if (filterObject.organization_id) { + result.where(`${this.tableName}.growing_organization_id`, 'in', [ + ...filterObject.organization_id, + ]); + delete filterObject.organization_id; + } + + result.where(filterObject); + } + + async getByFilter(filterCriteria: ContractFilter, options: FilterOptions) { + const knex = this.session.getDB(); + const { sort, ...filter } = filterCriteria; + + // there are two joins to connect the capture to the token and to the wallet right now so that we can double check our data entries + // the current data entered in the tables doesn't match up so there are some mismatches + let promise = knex + .select( + knex.raw( + ` + row_to_json(contract.*) AS contract, + row_to_json(agreement.*) AS agreement, + row_to_json(grower_account.*) AS worker, + row_to_json(stakeholder.*) AS stakeholder + FROM contracts.contract AS contract + LEFT JOIN contracts.agreement AS agreement + ON agreement.id = contract.agreement_id + LEFT JOIN stakeholder.stakeholder AS stakeholder + ON stakeholder.id = agreement.growing_organization_id + LEFT JOIN treetracker.grower_account AS grower_account + ON grower_account.id = contract.worker_id + `, + ), + ) + .where((builder) => this.filterWhereBuilder(filter, builder)); + + promise = promise.orderBy( + sort?.order_by || `${this.tableName}.id`, + sort?.order || 'desc', + ); + + const { limit, offset } = options; + if (limit) { + promise = promise.limit(limit); + } + if (offset) { + promise = promise.offset(offset); + } + + const captures = await promise; + + return captures; + } + + async getCount(filterCriteria: ContractFilter) { + const knex = this.session.getDB(); + const { ...filter } = filterCriteria; + + const result = await knex + .select( + knex.raw( + `COUNT(*) AS count + FROM contracts.contract AS contract + LEFT JOIN contracts.agreement AS agreement + ON agreement.id = contract.agreement_id + LEFT JOIN stakeholder.stakeholder AS stakeholder + ON stakeholder.id = agreement.growing_organization_id + LEFT JOIN treetracker.grower_account AS grower_account + ON grower_account.id = contract.worker_id + `, + ), + ) + .where((builder) => this.filterWhereBuilder(filter, builder)); + + return result[0].count; + } + + async getById(id: string | number) { + const object = await this.session + .getDB() + .select( + this.session.getDB().raw(` + contract.*, + agreement.*, + grower_account.*, + stakeholder.* + FROM contracts.contract AS contract + LEFT JOIN contracts.agreement AS agreement + ON agreement.id = contract.agreement_id + LEFT JOIN stakeholder.stakeholder AS stakeholder + ON stakeholder.id = agreement.growing_organization_id + LEFT JOIN treetracker.grower_account AS grower_account + ON grower_account.id = contract.worker_id + `), + ) + .where(`${this.tableName}.id`, id) + .first(); + + if (!object) { + throw new HttpError(404, `Can not find ${this.tableName} by id:${id}`); + } + return object; + } +} diff --git a/server/interfaces/Contract.ts b/server/interfaces/Contract.ts new file mode 100644 index 00000000..820a82d5 --- /dev/null +++ b/server/interfaces/Contract.ts @@ -0,0 +1,14 @@ +import DbModel from './DbModel'; + +export default interface Contract extends DbModel { + id: number; + agreement_id: number; + worker_id: number; + status: string; + notes: string; + created_at: string; + updated_at: string; + signed_at: string; + closed_at: string; + listed: true; +} diff --git a/server/interfaces/ContractFilter.ts b/server/interfaces/ContractFilter.ts new file mode 100644 index 00000000..29bdfbe5 --- /dev/null +++ b/server/interfaces/ContractFilter.ts @@ -0,0 +1,27 @@ +import DbModel from './DbModel'; + +interface ContractFilter extends DbModel { + // organization_id?: Array | undefined; + // grower_account_id?: string | undefined; + // id?: string | undefined; + // tree_id?: string | undefined; + // species_id?: string | undefined; + // tag?: string | undefined; + // device_identifier?: string | undefined; + // wallet?: string | undefined; + // token_id?: string | undefined; + // tokenized?: string | undefined; + + id?: number | undefined; + agreement_id?: number | undefined; + worker_id?: number | undefined; + status?: string | undefined; + notes?: string | undefined; + created_at?: string | undefined; + updated_at?: string | undefined; + signed_at?: string | undefined; + closed_at?: string | undefined; + listed?: true | false; +} + +export default ContractFilter; diff --git a/server/models/Contract.ts b/server/models/Contract.ts new file mode 100644 index 00000000..8e3afcc1 --- /dev/null +++ b/server/models/Contract.ts @@ -0,0 +1,29 @@ +import ContractRepository from 'infra/database/ContractRepository'; +import { delegateRepository } from 'infra/database/delegateRepository'; +import Contract from 'interfaces/Contract'; +import ContractFilter from 'interfaces/ContractFilter'; +import FilterOptions from 'interfaces/FilterOptions'; + +function getByFilter( + contractRepository: ContractRepository, +): (filter: ContractFilter, options: FilterOptions) => Promise { + return async function (filter: ContractFilter, options: FilterOptions) { + const contracts = await contractRepository.getByFilter(filter, options); + return contracts; + }; +} + +function getCount( + contractRepository: ContractRepository, +): (filter: ContractFilter) => Promise { + return async function (filter: ContractFilter) { + const count = await contractRepository.getCount(filter); + return count; + }; +} + +export default { + getByFilter, + getCount, + getById: delegateRepository('getById'), +}; diff --git a/server/routers/contractsRouter.ts b/server/routers/contractsRouter.ts new file mode 100644 index 00000000..64bcb1d2 --- /dev/null +++ b/server/routers/contractsRouter.ts @@ -0,0 +1,132 @@ +import express from 'express'; +import Joi from 'joi'; +import ContractRepository from 'infra/database/ContractRepository'; +import Session from 'infra/database/Session'; +import { handlerWrapper, queryFormatter } from './utils'; +import ContractModel from '../models/Contract'; + +const router = express.Router(); + +router.get( + '/count', + handlerWrapper(async (req, res) => { + const query = queryFormatter(req); + + // verify filter values + Joi.assert( + query, + Joi.object().keys({ + // capture filters + grower_account_id: Joi.string().uuid(), + // grower_account_id: Joi.string().uuid(), + organization_id: Joi.array(), + limit: Joi.number().integer().min(1).max(20000), + offset: Joi.number().integer().min(0), + startDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), + endDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), + id: Joi.string().uuid(), + // reference_id: Joi.string(), + // tree_id: Joi.string().uuid(), + // species_id: Joi.string().uuid(), + // tag_id: Joi.string().uuid(), + // device_identifier: Joi.string(), + wallet: Joi.string(), + // tokenized: Joi.string(), + // order_by: Joi.string(), + // order: Joi.string(), + token_id: Joi.string().uuid(), + // contract filters + agreement_id: Joi.string().uuid(), + worker_id: Joi.string().uuid(), // grower_account_id? + listed: Joi.boolean(), + + whereNulls: Joi.array(), + whereNotNulls: Joi.array(), + whereIns: Joi.array(), + }), + ); + const { ...rest } = req.query; + + const repo = new ContractRepository(new Session()); + const count = await ContractModel.getCount(repo)({ ...rest }); + res.send({ + count: Number(count), + }); + res.end(); + }), +); + +router.get( + '/:id', + handlerWrapper(async (req, res) => { + Joi.assert(req.params.id, Joi.string().required()); + const repo = new ContractRepository(new Session()); + const exe = ContractModel.getById(repo); + const result = await exe(req.params.id); + res.send(result); + res.end(); + }), +); + +router.get( + '/', + handlerWrapper(async (req, res) => { + const query = queryFormatter(req); + console.log('************************* /contract'); + + // verify filter values + Joi.assert( + query, + Joi.object().keys({ + // capture filters + // grower_account_id: Joi.string().uuid(), + organization_id: Joi.array(), + limit: Joi.number().integer().min(1).max(20000), + offset: Joi.number().integer().min(0), + startDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), + endDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), + id: Joi.string().uuid(), + // reference_id: Joi.string(), + // tree_id: Joi.string().uuid(), + // species_id: Joi.string().uuid(), + // tag_id: Joi.string().uuid(), + // device_identifier: Joi.string(), + wallet: Joi.string(), + // tokenized: Joi.string(), + // order_by: Joi.string(), + // order: Joi.string(), + token_id: Joi.string().uuid(), + // contract filters + agreement_id: Joi.string().uuid(), + worker_id: Joi.string().uuid(), // grower_account_id? + listed: Joi.boolean(), + + whereNulls: Joi.array(), + whereNotNulls: Joi.array(), + whereIns: Joi.array(), + }), + ); + const { + limit = 25, + offset = 0, + order = 'desc', + order_by = 'contract.id', + ...rest + } = query; + + const repo = new ContractRepository(new Session()); + const exe = ContractModel.getByFilter(repo); + const sort = { order, order_by }; + const result = await exe({ ...rest, sort }, { limit, offset }); + const count = await ContractModel.getCount(repo)({ ...rest }); + res.send({ + Contracts: result, + total: Number(count), + offset, + limit, + }); + res.end(); + }), +); + +export default router; From 7f264edc8c2b16c7560e52bc7b34494e3c8872d9 Mon Sep 17 00:00:00 2001 From: Gwynn Dandridge-Perry Date: Fri, 21 Apr 2023 12:15:49 -0700 Subject: [PATCH 64/65] feat: update contract query result format --- server/infra/database/ContractRepository.ts | 65 ++++++++++----------- server/interfaces/ContractFilter.ts | 11 ---- server/routers/contractsRouter.ts | 60 +++++-------------- 3 files changed, 46 insertions(+), 90 deletions(-) diff --git a/server/infra/database/ContractRepository.ts b/server/infra/database/ContractRepository.ts index 649a4c25..65fac814 100644 --- a/server/infra/database/ContractRepository.ts +++ b/server/infra/database/ContractRepository.ts @@ -27,7 +27,7 @@ export default class ContractRepository extends BaseRepository { } delete parameters.tokenized; - // result.whereNot(`${this.tableName}.status`, 'deleted'); + result.whereNot(`${this.tableName}.status`, 'deleted'); whereNotNulls.forEach((whereNot) => { // to map table names to fields for query @@ -38,8 +38,6 @@ export default class ContractRepository extends BaseRepository { default: result.whereNotNull(whereNot); } - - // result.whereNotNull(whereNot); }); whereNulls.forEach((whereNull) => { @@ -51,7 +49,6 @@ export default class ContractRepository extends BaseRepository { default: result.whereNull(whereNull); } - // result.whereNull(whereNull); }); whereIns.forEach((whereIn) => { @@ -73,25 +70,11 @@ export default class ContractRepository extends BaseRepository { delete filterObject.endDate; } - // if (filterObject.tag_id) { - // filterObject[`treetracker.capture_tag.tag_id`] = filterObject.tag_id; - // delete filterObject.tag_id; - // } - if (filterObject.id) { result.where(`${this.tableName}.id`, '=', filterObject.id); delete filterObject.id; } - // if (filterObject.reference_id) { - // result.where( - // `${this.tableName}.reference_id`, - // '=', - // filterObject.reference_id, - // ); - // delete filterObject.reference_id; - // } - if (filterObject.organization_id) { result.where(`${this.tableName}.growing_organization_id`, 'in', [ ...filterObject.organization_id, @@ -106,30 +89,35 @@ export default class ContractRepository extends BaseRepository { const knex = this.session.getDB(); const { sort, ...filter } = filterCriteria; - // there are two joins to connect the capture to the token and to the wallet right now so that we can double check our data entries - // the current data entered in the tables doesn't match up so there are some mismatches let promise = knex .select( knex.raw( ` - row_to_json(contract.*) AS contract, + ${this.tableName}.id, + ${this.tableName}.status, + ${this.tableName}.notes, + ${this.tableName}.created_at, + ${this.tableName}.updated_at, + ${this.tableName}.signed_at, + ${this.tableName}.closed_at, + ${this.tableName}.listed, row_to_json(agreement.*) AS agreement, row_to_json(grower_account.*) AS worker, row_to_json(stakeholder.*) AS stakeholder - FROM contracts.contract AS contract + FROM ${this.tableName} LEFT JOIN contracts.agreement AS agreement - ON agreement.id = contract.agreement_id + ON agreement.id = ${this.tableName}.agreement_id LEFT JOIN stakeholder.stakeholder AS stakeholder ON stakeholder.id = agreement.growing_organization_id LEFT JOIN treetracker.grower_account AS grower_account - ON grower_account.id = contract.worker_id + ON grower_account.id = ${this.tableName}.worker_id `, ), ) .where((builder) => this.filterWhereBuilder(filter, builder)); promise = promise.orderBy( - sort?.order_by || `${this.tableName}.id`, + `${this.tableName}.${sort?.order_by}` || `${this.tableName}.id`, sort?.order || 'desc', ); @@ -154,13 +142,13 @@ export default class ContractRepository extends BaseRepository { .select( knex.raw( `COUNT(*) AS count - FROM contracts.contract AS contract + FROM ${this.tableName} LEFT JOIN contracts.agreement AS agreement - ON agreement.id = contract.agreement_id + ON agreement.id = ${this.tableName}.agreement_id LEFT JOIN stakeholder.stakeholder AS stakeholder ON stakeholder.id = agreement.growing_organization_id LEFT JOIN treetracker.grower_account AS grower_account - ON grower_account.id = contract.worker_id + ON grower_account.id = ${this.tableName}.worker_id `, ), ) @@ -174,17 +162,24 @@ export default class ContractRepository extends BaseRepository { .getDB() .select( this.session.getDB().raw(` - contract.*, - agreement.*, - grower_account.*, - stakeholder.* - FROM contracts.contract AS contract + ${this.tableName}.id, + ${this.tableName}.status, + ${this.tableName}.notes, + ${this.tableName}.created_at, + ${this.tableName}.updated_at, + ${this.tableName}.signed_at, + ${this.tableName}.closed_at, + ${this.tableName}.listed, + row_to_json(agreement.*) AS agreement, + row_to_json(grower_account.*) AS worker, + row_to_json(stakeholder.*) AS stakeholder + FROM ${this.tableName} LEFT JOIN contracts.agreement AS agreement - ON agreement.id = contract.agreement_id + ON agreement.id = ${this.tableName}.agreement_id LEFT JOIN stakeholder.stakeholder AS stakeholder ON stakeholder.id = agreement.growing_organization_id LEFT JOIN treetracker.grower_account AS grower_account - ON grower_account.id = contract.worker_id + ON grower_account.id = ${this.tableName}.worker_id `), ) .where(`${this.tableName}.id`, id) diff --git a/server/interfaces/ContractFilter.ts b/server/interfaces/ContractFilter.ts index 29bdfbe5..e2ae7b63 100644 --- a/server/interfaces/ContractFilter.ts +++ b/server/interfaces/ContractFilter.ts @@ -1,17 +1,6 @@ import DbModel from './DbModel'; interface ContractFilter extends DbModel { - // organization_id?: Array | undefined; - // grower_account_id?: string | undefined; - // id?: string | undefined; - // tree_id?: string | undefined; - // species_id?: string | undefined; - // tag?: string | undefined; - // device_identifier?: string | undefined; - // wallet?: string | undefined; - // token_id?: string | undefined; - // tokenized?: string | undefined; - id?: number | undefined; agreement_id?: number | undefined; worker_id?: number | undefined; diff --git a/server/routers/contractsRouter.ts b/server/routers/contractsRouter.ts index 64bcb1d2..a9cd21e2 100644 --- a/server/routers/contractsRouter.ts +++ b/server/routers/contractsRouter.ts @@ -12,34 +12,20 @@ router.get( handlerWrapper(async (req, res) => { const query = queryFormatter(req); - // verify filter values Joi.assert( query, Joi.object().keys({ - // capture filters - grower_account_id: Joi.string().uuid(), - // grower_account_id: Joi.string().uuid(), - organization_id: Joi.array(), - limit: Joi.number().integer().min(1).max(20000), - offset: Joi.number().integer().min(0), - startDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), - endDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), + // contract table filters id: Joi.string().uuid(), - // reference_id: Joi.string(), - // tree_id: Joi.string().uuid(), - // species_id: Joi.string().uuid(), - // tag_id: Joi.string().uuid(), - // device_identifier: Joi.string(), - wallet: Joi.string(), - // tokenized: Joi.string(), - // order_by: Joi.string(), - // order: Joi.string(), - token_id: Joi.string().uuid(), - // contract filters agreement_id: Joi.string().uuid(), worker_id: Joi.string().uuid(), // grower_account_id? listed: Joi.boolean(), - + // organization_id: Joi.array(), + startDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), + endDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), + // defaults + limit: Joi.number().integer().min(1).max(20000), + offset: Joi.number().integer().min(0), whereNulls: Joi.array(), whereNotNulls: Joi.array(), whereIns: Joi.array(), @@ -72,35 +58,21 @@ router.get( '/', handlerWrapper(async (req, res) => { const query = queryFormatter(req); - console.log('************************* /contract'); - // verify filter values Joi.assert( query, Joi.object().keys({ - // capture filters - // grower_account_id: Joi.string().uuid(), - organization_id: Joi.array(), - limit: Joi.number().integer().min(1).max(20000), - offset: Joi.number().integer().min(0), - startDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), - endDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), + // contract table filters id: Joi.string().uuid(), - // reference_id: Joi.string(), - // tree_id: Joi.string().uuid(), - // species_id: Joi.string().uuid(), - // tag_id: Joi.string().uuid(), - // device_identifier: Joi.string(), - wallet: Joi.string(), - // tokenized: Joi.string(), - // order_by: Joi.string(), - // order: Joi.string(), - token_id: Joi.string().uuid(), - // contract filters agreement_id: Joi.string().uuid(), worker_id: Joi.string().uuid(), // grower_account_id? listed: Joi.boolean(), - + // organization_id: Joi.array(), + startDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), + endDate: Joi.string().regex(/^\d{4}-\d{2}-\d{2}$/), + // defaults + limit: Joi.number().integer().min(1).max(20000), + offset: Joi.number().integer().min(0), whereNulls: Joi.array(), whereNotNulls: Joi.array(), whereIns: Joi.array(), @@ -110,7 +82,7 @@ router.get( limit = 25, offset = 0, order = 'desc', - order_by = 'contract.id', + order_by = 'id', ...rest } = query; @@ -120,7 +92,7 @@ router.get( const result = await exe({ ...rest, sort }, { limit, offset }); const count = await ContractModel.getCount(repo)({ ...rest }); res.send({ - Contracts: result, + contracts: result, total: Number(count), offset, limit, From a54e2b9da1bc6c20c692e1e23f581df5207b7781 Mon Sep 17 00:00:00 2001 From: Gwynn Dandridge-Perry Date: Fri, 10 Nov 2023 13:13:22 -0800 Subject: [PATCH 65/65] fix: ids should be strings --- server/infra/database/ContractRepository.ts | 2 +- server/interfaces/ContractFilter.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/infra/database/ContractRepository.ts b/server/infra/database/ContractRepository.ts index 65fac814..b3b35eef 100644 --- a/server/infra/database/ContractRepository.ts +++ b/server/infra/database/ContractRepository.ts @@ -157,7 +157,7 @@ export default class ContractRepository extends BaseRepository { return result[0].count; } - async getById(id: string | number) { + async getById(id: string) { const object = await this.session .getDB() .select( diff --git a/server/interfaces/ContractFilter.ts b/server/interfaces/ContractFilter.ts index e2ae7b63..ff72c36a 100644 --- a/server/interfaces/ContractFilter.ts +++ b/server/interfaces/ContractFilter.ts @@ -1,9 +1,9 @@ import DbModel from './DbModel'; interface ContractFilter extends DbModel { - id?: number | undefined; - agreement_id?: number | undefined; - worker_id?: number | undefined; + id?: string | undefined; + agreement_id?: string | undefined; + worker_id?: string | undefined; status?: string | undefined; notes?: string | undefined; created_at?: string | undefined;