From e12a116b3edc30502b2af454bd5e069f1acb001c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20Co=C5=9Fkun?= Date: Fri, 19 Jun 2020 16:49:07 +0300 Subject: [PATCH 1/5] nci-agency/anet#3043: Configure mssql and psql for geosearch queries - Enable PostGIS extension on PostgreSQL - Add db migration for adding geometry column to locations - Add db migration to populate geometry from existing lat,lng columns - Update test data with geometry values - Update test data conversion script for geometry values - Add gradle task for dropping postgis extension and make sure that it runs before dbDrop task otherwise drop-all liquibase command fails. --- build.gradle | 13 ++++++++++- insertBaseData-mssql.sql | 36 +++++++++++++++---------------- mssql2pg.pl | 2 ++ prepare-psql.sql | 2 ++ src/main/resources/migrations.xml | 12 +++++++++++ 5 files changed, 46 insertions(+), 19 deletions(-) diff --git a/build.gradle b/build.gradle index 1b6c8a6f1b..275636f28d 100644 --- a/build.gradle +++ b/build.gradle @@ -270,7 +270,18 @@ task dbRollback(dependsOn: 'compileJava', type: JavaExec) { } } +task dbDrop_postgis(dependsOn: "compileJava", type: com.bmuschko.gradle.docker.tasks.container.DockerExecContainer) { + group = "database" + description = "Drops PostGIS extension and related objects on PostgreSQL." + targetContainerId { dbContainerName } + commands = [ ["psql", "-U", run.environment["ANET_DB_USERNAME"], "-d", run.environment["ANET_DB_NAME"], "-c", "DROP EXTENSION IF EXISTS postgis CASCADE"] as String[] ] +} + task dbDrop(dependsOn: 'compileJava', type: JavaExec) { + if(!isMssql) { + dependsOn 'dbDrop_postgis' + tasks.findByName('dbDrop_postgis').mustRunAfter('compileJava') + } group = "database" description = "Runs the ANET database drop-all (Liquibase) command." classpath = sourceSets.main.runtimeClasspath @@ -339,7 +350,7 @@ task dockerPushImage(type: com.bmuschko.gradle.docker.tasks.image.DockerPushImag task dockerPullDB(type: com.bmuschko.gradle.docker.tasks.image.DockerPullImage) { group = "database container" - image = isMssql ? "ncia/anet-mssql-linux:latest" : "postgres:latest" + image = isMssql ? "ncia/anet-mssql-linux:latest" : "postgis/postgis:latest" description = "Pulls a docker image for the ANET DB from ${image}." } diff --git a/insertBaseData-mssql.sql b/insertBaseData-mssql.sql index c01ea897e3..1311aa11f1 100644 --- a/insertBaseData-mssql.sql +++ b/insertBaseData-mssql.sql @@ -437,24 +437,24 @@ INSERT INTO approvers (approvalStepUuid, positionUuid) AND approvalSteps.type = 1; -- Create locations -INSERT INTO locations (uuid, name, lat, lng, createdAt, updatedAt) - VALUES (N'cc49bb27-4d8f-47a8-a9ee-af2b68b992ac', 'St Johns Airport', 47.613442, -52.740936, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO locations (uuid, name, lat, lng, createdAt, updatedAt) - VALUES (N'8c138750-91ce-41bf-9b4c-9f0ddc73608b', 'Murray''s Hotel', 47.561517, -52.708760, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO locations (uuid, name, lat, lng, createdAt, updatedAt) - VALUES (N'9c982685-5946-4dad-a7ee-0f5a12f5e170', 'Wishingwells Park', 47.560040, -52.736962, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO locations (uuid, name, lat, lng, createdAt, updatedAt) - VALUES (N'0855fb0a-995e-4a79-a132-4024ee2983ff', 'General Hospital', 47.571772, -52.741935, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO locations (uuid, name, lat, lng, createdAt, updatedAt) - VALUES (N'95446f93-249b-4aa9-b98a-7bd2c4680718', 'Portugal Cove Ferry Terminal', 47.626718, -52.857241, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO locations (uuid, name, lat, lng, createdAt, updatedAt) - VALUES (N'c8fdb53f-6f93-46fc-b0fa-f005c7b49667', 'Cabot Tower', 47.570010, -52.681770, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO locations (uuid, name, lat, lng, createdAt, updatedAt) - VALUES (N'c7a9f420-457a-490c-a810-b504c022cf1e', 'Fort Amherst', 47.563763, -52.680590, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO locations (uuid, name, lat, lng, createdAt, updatedAt) - VALUES (N'7339f9e3-99d1-497a-9e3b-1269c4c287fe', 'Harbour Grace Police Station', 47.705133, -53.214422, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); -INSERT INTO locations (uuid, name, lat, lng, createdAt, updatedAt) - VALUES (N'f2207d9b-204b-4cb5-874d-3fe6bc6f8acd', 'Conception Bay South Police Station', 47.526784, -52.954739, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO locations (uuid, name, lat, lng, geometry, createdAt, updatedAt) + VALUES (N'cc49bb27-4d8f-47a8-a9ee-af2b68b992ac', 'St Johns Airport', 47.613442, -52.740936, geometry::Point(-52.740936, 47.613442, 3857), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO locations (uuid, name, lat, lng, geometry, createdAt, updatedAt) + VALUES (N'8c138750-91ce-41bf-9b4c-9f0ddc73608b', 'Murray''s Hotel', 47.561517, -52.708760, geometry::Point(-52.708760, 47.561517, 3857), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO locations (uuid, name, lat, lng, geometry, createdAt, updatedAt) + VALUES (N'9c982685-5946-4dad-a7ee-0f5a12f5e170', 'Wishingwells Park', 47.560040, -52.736962, geometry::Point(-52.736962, 47.560040, 3857), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO locations (uuid, name, lat, lng, geometry, createdAt, updatedAt) + VALUES (N'0855fb0a-995e-4a79-a132-4024ee2983ff', 'General Hospital', 47.571772, -52.741935, geometry::Point(-52.741935, 47.571772, 3857), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO locations (uuid, name, lat, lng, geometry, createdAt, updatedAt) + VALUES (N'95446f93-249b-4aa9-b98a-7bd2c4680718', 'Portugal Cove Ferry Terminal', 47.626718, -52.857241, geometry::Point(-52.857241, 47.626718, 3857), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO locations (uuid, name, lat, lng, geometry, createdAt, updatedAt) + VALUES (N'c8fdb53f-6f93-46fc-b0fa-f005c7b49667', 'Cabot Tower', 47.570010, -52.681770, geometry::Point(-52.681770, 47.570010, 3857), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO locations (uuid, name, lat, lng, geometry, createdAt, updatedAt) + VALUES (N'c7a9f420-457a-490c-a810-b504c022cf1e', 'Fort Amherst', 47.563763, -52.680590, geometry::Point(-52.680590, 47.563763, 3857), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO locations (uuid, name, lat, lng, geometry, createdAt, updatedAt) + VALUES (N'7339f9e3-99d1-497a-9e3b-1269c4c287fe', 'Harbour Grace Police Station', 47.705133, -53.214422, geometry::Point(-53.214422, 47.705133, 3857), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); +INSERT INTO locations (uuid, name, lat, lng, geometry, createdAt, updatedAt) + VALUES (N'f2207d9b-204b-4cb5-874d-3fe6bc6f8acd', 'Conception Bay South Police Station', 47.526784, -52.954739, geometry::Point(-52.954739, 47.526784, 3857), CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); INSERT INTO locations (uuid, name, createdAt, updatedAt) VALUES (N'e0ff0d6c-e663-4639-a44d-b075bf1e690d', 'MoD Headquarters Kabul', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP); INSERT INTO locations (uuid, name, createdAt, updatedAt) diff --git a/mssql2pg.pl b/mssql2pg.pl index 4b541ce325..4265b9c550 100755 --- a/mssql2pg.pl +++ b/mssql2pg.pl @@ -42,3 +42,5 @@ s/cast\((\S+) as datetime2\((\d+)\)\)/"date_trunc(" . ($2 eq '3' ? "'milliseconds'" : "'second'") . ", $1)"/ie; # Function to generate uuid's s/lower\(newid\(\)\)/uuid_generate_v4()/g; +# convert point geometry functions +s/geometry::Point\((-\d{2}\.\d{6}, \d{2}\.\d{6})/ST_SetSRID(ST_MakePoint($1)/g; diff --git a/prepare-psql.sql b/prepare-psql.sql index 5c06ab1367..b932a8c877 100644 --- a/prepare-psql.sql +++ b/prepare-psql.sql @@ -11,3 +11,5 @@ CREATE OR REPLACE AGGREGATE tsvector_agg (tsvector) ( -- make sure the preconditions for UUID prefix search are met CREATE EXTENSION IF NOT EXISTS pg_trgm; + +CREATE EXTENSION IF NOT EXISTS postgis; diff --git a/src/main/resources/migrations.xml b/src/main/resources/migrations.xml index 3bd72d8b1b..16b088f635 100644 --- a/src/main/resources/migrations.xml +++ b/src/main/resources/migrations.xml @@ -3640,4 +3640,16 @@ + + + + + + UPDATE locations SET "geometry" = ST_SetSRID(ST_MakePoint(lng, lat), 3857); + + + UPDATE locations SET "geometry" = geometry::Point(lng, lat, 3857) WHERE lat IS NOT NULL AND lng IS NOT NULL; + + + From 63f2ba540e3b31d6e2afe28bfa12aeb025cea6e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20Co=C5=9Fkun?= Date: Thu, 25 Jun 2020 16:11:59 +0300 Subject: [PATCH 2/5] nci-agency/anet#3043: Add geosearch query for locations --- .../anet/beans/search/LocationSearchQuery.java | 15 +++++++++++++++ .../dds/anet/search/AbstractLocationSearcher.java | 6 ++++++ .../mil/dds/anet/search/AbstractSearcher.java | 12 ++++++++++++ .../anet/search/mssql/MssqlLocationSearcher.java | 5 +++++ .../search/pg/PostgresqlLocationSearcher.java | 5 +++++ 5 files changed, 43 insertions(+) diff --git a/src/main/java/mil/dds/anet/beans/search/LocationSearchQuery.java b/src/main/java/mil/dds/anet/beans/search/LocationSearchQuery.java index 5c0d84e01f..03b6bf176a 100644 --- a/src/main/java/mil/dds/anet/beans/search/LocationSearchQuery.java +++ b/src/main/java/mil/dds/anet/beans/search/LocationSearchQuery.java @@ -1,11 +1,26 @@ package mil.dds.anet.beans.search; +import io.leangen.graphql.annotations.GraphQLInputField; +import io.leangen.graphql.annotations.GraphQLQuery; + public class LocationSearchQuery extends AbstractSearchQuery { + @GraphQLQuery + @GraphQLInputField + private String withinPolygon; + public LocationSearchQuery() { super(LocationSearchSortBy.NAME); } + public String getWithinPolygon() { + return withinPolygon; + } + + public void setWithinPolygon(String withinPolygon) { + this.withinPolygon = withinPolygon; + } + @Override public LocationSearchQuery clone() throws CloneNotSupportedException { return (LocationSearchQuery) super.clone(); diff --git a/src/main/java/mil/dds/anet/search/AbstractLocationSearcher.java b/src/main/java/mil/dds/anet/search/AbstractLocationSearcher.java index f8c4d6d4e6..4e8b2e7a7c 100644 --- a/src/main/java/mil/dds/anet/search/AbstractLocationSearcher.java +++ b/src/main/java/mil/dds/anet/search/AbstractLocationSearcher.java @@ -44,9 +44,15 @@ protected void buildQuery(LocationSearchQuery query) { qb.addSqlArg("userUuid", DaoUtils.getUuid(query.getUser())); } + if (query.getWithinPolygon() != null) { + addWithinPolygon(query); + } + addOrderByClauses(qb, query); } + protected abstract void addWithinPolygon(LocationSearchQuery query); + protected void addOrderByClauses(AbstractSearchQueryBuilder qb, LocationSearchQuery query) { switch (query.getSortBy()) { case CREATED_AT: diff --git a/src/main/java/mil/dds/anet/search/AbstractSearcher.java b/src/main/java/mil/dds/anet/search/AbstractSearcher.java index bd6beb31c5..425162dcee 100644 --- a/src/main/java/mil/dds/anet/search/AbstractSearcher.java +++ b/src/main/java/mil/dds/anet/search/AbstractSearcher.java @@ -97,6 +97,18 @@ private String getTsQuery() { return String.format("(%1$s || %2$s)", tsQueryAnet, tsQuerySimple); } + protected void addWithinPolygonMssql(String locationUuidColumn, String queryText) { + qb.addWhereClause(String.format( + "\"%1$s\" IN (SELECT \"uuid\" FROM locations WHERE \"geometry\".STWithin(geometry::STGeomFromText('%2$s', 3857)) = 1)", + locationUuidColumn, queryText)); + } + + protected void addWithinPolygonPsql(String locationUuidColumn, String queryText) { + qb.addWhereClause(String.format( + "\"%1$s\" IN (SELECT \"uuid\" FROM locations WHERE ST_Within(\"geometry\", ST_GeomFromText('%2$s', 3857)))", + locationUuidColumn, queryText)); + } + protected List getOrderBy(SortOrder sortOrder, String table, String... columns) { final List clauses = new ArrayList<>(); for (final String column : columns) { diff --git a/src/main/java/mil/dds/anet/search/mssql/MssqlLocationSearcher.java b/src/main/java/mil/dds/anet/search/mssql/MssqlLocationSearcher.java index 4fade5756a..af38aaf886 100644 --- a/src/main/java/mil/dds/anet/search/mssql/MssqlLocationSearcher.java +++ b/src/main/java/mil/dds/anet/search/mssql/MssqlLocationSearcher.java @@ -26,6 +26,11 @@ protected void addTextQuery(LocationSearchQuery query) { qb.addSqlArg("containsQuery", qb.getContainsQuery(text)); } + @Override + protected void addWithinPolygon(LocationSearchQuery query) { + addWithinPolygonMssql("uuid", query.getWithinPolygon()); + } + @Override protected void addOrderByClauses(AbstractSearchQueryBuilder qb, LocationSearchQuery query) { if (hasTextQuery(query) && !query.isSortByPresent()) { diff --git a/src/main/java/mil/dds/anet/search/pg/PostgresqlLocationSearcher.java b/src/main/java/mil/dds/anet/search/pg/PostgresqlLocationSearcher.java index e2e317bb4d..5d360adeef 100644 --- a/src/main/java/mil/dds/anet/search/pg/PostgresqlLocationSearcher.java +++ b/src/main/java/mil/dds/anet/search/pg/PostgresqlLocationSearcher.java @@ -18,6 +18,11 @@ protected void addTextQuery(LocationSearchQuery query) { addFullTextSearch("locations", query.getText(), query.isSortByPresent()); } + @Override + protected void addWithinPolygon(LocationSearchQuery query) { + addWithinPolygonPsql("uuid", query.getWithinPolygon()); + } + @Override protected void addOrderByClauses(AbstractSearchQueryBuilder qb, LocationSearchQuery query) { if (hasTextQuery(query) && !query.isSortByPresent()) { From 04409f13a6bcd7897a3e4649a4c3403dea379f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20Co=C5=9Fkun?= Date: Thu, 25 Jun 2020 15:35:59 +0300 Subject: [PATCH 3/5] nci-agency/anet#3043: Add geosearch query for reports --- .../mil/dds/anet/beans/search/ReportSearchQuery.java | 12 ++++++++++++ .../mil/dds/anet/search/AbstractReportSearcher.java | 6 ++++++ .../dds/anet/search/mssql/MssqlReportSearcher.java | 5 +++++ .../dds/anet/search/pg/PostgresqlReportSearcher.java | 6 ++++++ 4 files changed, 29 insertions(+) diff --git a/src/main/java/mil/dds/anet/beans/search/ReportSearchQuery.java b/src/main/java/mil/dds/anet/beans/search/ReportSearchQuery.java index 2cb635283f..df43f3b168 100644 --- a/src/main/java/mil/dds/anet/beans/search/ReportSearchQuery.java +++ b/src/main/java/mil/dds/anet/beans/search/ReportSearchQuery.java @@ -110,6 +110,10 @@ public class ReportSearchQuery extends AbstractSearchQuery { @GraphQLQuery @GraphQLInputField private Boolean sensitiveInfo; + @GraphQLQuery + @GraphQLInputField + private String withinPolygon; + // internal search parameter: private boolean systemSearch; @@ -358,6 +362,14 @@ public void setSensitiveInfo(Boolean sensitiveInfo) { this.sensitiveInfo = sensitiveInfo; } + public String getWithinPolygon() { + return withinPolygon; + } + + public void setWithinPolygon(String withinPolygon) { + this.withinPolygon = withinPolygon; + } + @JsonIgnore public boolean isSystemSearch() { return systemSearch; diff --git a/src/main/java/mil/dds/anet/search/AbstractReportSearcher.java b/src/main/java/mil/dds/anet/search/AbstractReportSearcher.java index b972f0e449..e5400e3a21 100644 --- a/src/main/java/mil/dds/anet/search/AbstractReportSearcher.java +++ b/src/main/java/mil/dds/anet/search/AbstractReportSearcher.java @@ -291,9 +291,15 @@ protected void buildQuery(Set subFields, ReportSearchQuery query) { } } + if (query.getWithinPolygon() != null) { + addWithinPolygon(query); + } + addOrderByClauses(qb, query); } + protected abstract void addWithinPolygon(ReportSearchQuery query); + protected abstract void addBatchClause(ReportSearchQuery query); @SuppressWarnings("unchecked") diff --git a/src/main/java/mil/dds/anet/search/mssql/MssqlReportSearcher.java b/src/main/java/mil/dds/anet/search/mssql/MssqlReportSearcher.java index 704df1580a..0d366b4ca7 100644 --- a/src/main/java/mil/dds/anet/search/mssql/MssqlReportSearcher.java +++ b/src/main/java/mil/dds/anet/search/mssql/MssqlReportSearcher.java @@ -71,6 +71,11 @@ protected void addTextQuery(ReportSearchQuery query) { qb.addSqlArg("fullTextQuery", qb.getFullTextQuery(text)); } + @Override + protected void addWithinPolygon(ReportSearchQuery query) { + addWithinPolygonMssql("locationUuid", query.getWithinPolygon()); + } + @Override protected void addBatchClause(ReportSearchQuery query) { addBatchClause(outerQb, query); diff --git a/src/main/java/mil/dds/anet/search/pg/PostgresqlReportSearcher.java b/src/main/java/mil/dds/anet/search/pg/PostgresqlReportSearcher.java index 9f95d6d924..732d03a7c1 100644 --- a/src/main/java/mil/dds/anet/search/pg/PostgresqlReportSearcher.java +++ b/src/main/java/mil/dds/anet/search/pg/PostgresqlReportSearcher.java @@ -6,6 +6,7 @@ import mil.dds.anet.beans.Report; import mil.dds.anet.beans.lists.AnetBeanList; import mil.dds.anet.beans.search.ISearchQuery.SortOrder; +import mil.dds.anet.beans.search.LocationSearchQuery; import mil.dds.anet.beans.search.ReportSearchQuery; import mil.dds.anet.database.mappers.ReportMapper; import mil.dds.anet.search.AbstractReportSearcher; @@ -43,6 +44,11 @@ protected void addTextQuery(ReportSearchQuery query) { addFullTextSearch("reports", query.getText(), query.isSortByPresent()); } + @Override + protected void addWithinPolygon(ReportSearchQuery query) { + addWithinPolygonPsql("locationUuid", query.getWithinPolygon()); + } + @Override protected void addBatchClause(ReportSearchQuery query) { addBatchClause(qb, query); From cda4cdc0cd585cee851fceefe5b3ef57b119d2cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20Co=C5=9Fkun?= Date: Thu, 25 Jun 2020 15:57:42 +0300 Subject: [PATCH 4/5] nci-agency/anet#3043: Add geosearch query for positions --- .../dds/anet/beans/search/PositionSearchQuery.java | 11 +++++++++++ .../mil/dds/anet/search/AbstractPositionSearcher.java | 6 ++++++ .../dds/anet/search/mssql/MssqlPositionSearcher.java | 6 ++++++ .../anet/search/pg/PostgresqlPositionSearcher.java | 5 +++++ 4 files changed, 28 insertions(+) diff --git a/src/main/java/mil/dds/anet/beans/search/PositionSearchQuery.java b/src/main/java/mil/dds/anet/beans/search/PositionSearchQuery.java index b0aedab6ed..0e5bc61c47 100644 --- a/src/main/java/mil/dds/anet/beans/search/PositionSearchQuery.java +++ b/src/main/java/mil/dds/anet/beans/search/PositionSearchQuery.java @@ -33,6 +33,9 @@ public class PositionSearchQuery extends AbstractSearchQuery) query.getBatchParams()); diff --git a/src/main/java/mil/dds/anet/search/mssql/MssqlPositionSearcher.java b/src/main/java/mil/dds/anet/search/mssql/MssqlPositionSearcher.java index 3af2a449eb..38424379b0 100644 --- a/src/main/java/mil/dds/anet/search/mssql/MssqlPositionSearcher.java +++ b/src/main/java/mil/dds/anet/search/mssql/MssqlPositionSearcher.java @@ -3,6 +3,7 @@ import mil.dds.anet.beans.Position; import mil.dds.anet.beans.search.ISearchQuery.SortOrder; import mil.dds.anet.beans.search.PositionSearchQuery; +import mil.dds.anet.beans.search.ReportSearchQuery; import mil.dds.anet.search.AbstractPositionSearcher; import mil.dds.anet.search.AbstractSearchQueryBuilder; @@ -39,6 +40,11 @@ protected void addTextQuery(PositionSearchQuery query) { qb.addSqlArg("likeQuery", qb.getLikeQuery(text)); } + @Override + protected void addWithinPolygon(PositionSearchQuery query) { + addWithinPolygonMssql("locationUuid", query.getWithinPolygon()); + } + @Override protected void addOrderByClauses(AbstractSearchQueryBuilder qb, PositionSearchQuery query) { if (hasTextQuery(query) && !query.isSortByPresent()) { diff --git a/src/main/java/mil/dds/anet/search/pg/PostgresqlPositionSearcher.java b/src/main/java/mil/dds/anet/search/pg/PostgresqlPositionSearcher.java index ac74ee9dfb..134df3366d 100644 --- a/src/main/java/mil/dds/anet/search/pg/PostgresqlPositionSearcher.java +++ b/src/main/java/mil/dds/anet/search/pg/PostgresqlPositionSearcher.java @@ -18,6 +18,11 @@ protected void addTextQuery(PositionSearchQuery query) { addFullTextSearch("positions", query.getText(), query.isSortByPresent()); } + @Override + protected void addWithinPolygon(PositionSearchQuery query) { + addWithinPolygonPsql("locationUuid", query.getWithinPolygon()); + } + @Override protected void addOrderByClauses(AbstractSearchQueryBuilder qb, PositionSearchQuery query) { if (hasTextQuery(query) && !query.isSortByPresent()) { From 304ce58d98ff3e2841bd93959243761edf7eb01d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20Co=C5=9Fkun?= Date: Thu, 25 Jun 2020 20:42:25 +0300 Subject: [PATCH 5/5] nci-agency/anet#3043: Add e2e api tests for geosearch queries --- client/package.json | 1 + .../webdriver/specs/geoSearchApi.spec.js | 187 ++++++++++++++++++ client/yarn.lock | 9 +- insertBaseData-mssql.sql | 1 + 4 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 client/tests/webdriver/specs/geoSearchApi.spec.js diff --git a/client/package.json b/client/package.json index 0ca6115cfa..67e0597cb9 100644 --- a/client/package.json +++ b/client/package.json @@ -38,6 +38,7 @@ "@wdio/sync": "6.10.0", "aigle": "1.14.1", "autoprefixer": "9.8.6", + "axios": "0.21.0", "ava": "3.13.0", "babel-jest": "26.6.3", "babel-loader": "8.2.1", diff --git a/client/tests/webdriver/specs/geoSearchApi.spec.js b/client/tests/webdriver/specs/geoSearchApi.spec.js new file mode 100644 index 0000000000..39ecbfa0a2 --- /dev/null +++ b/client/tests/webdriver/specs/geoSearchApi.spec.js @@ -0,0 +1,187 @@ +import { expect } from "chai" +import lodash from "lodash" + +const axios = require("axios") + +const apiUrl = `${process.env.SERVER_URL}/graphql?user=erin&pass=erin` + +// centered on General Hospital, zoom level 15, not padded +const polygon01 = + "POLYGON ((-52.77621746063233 47.56453866910163, -52.741935 47.56453866910163, -52.70763874053956 47.56453866910163, -52.70763874053956 47.571772, -52.70763874053956 47.57901543200339, -52.741935 47.57901543200339, -52.77621746063233 47.57901543200339, -52.77621746063233 47.571772, -52.77621746063233 47.56453866910163))" + +// centered on General Hospital, zoom level 15, padded by 0.5 +const polygon02 = + "POLYGON ((-52.81050682067872 47.55730028765075, -52.741935 47.55730028765075, -52.67334938049317 47.55730028765075, -52.67334938049317 47.571772, -52.67334938049317 47.58625381345426, -52.741935 47.58625381345426, -52.81050682067872 47.58625381345426, -52.81050682067872 47.571772, -52.81050682067872 47.55730028765075))" + +// centered on General Hospital, zoom level 11, padded by 0.5 +const polygon03 = + "POLYGON ((-57.13165283203125 46.642388783472754, -52.741935 46.642388783472754, -48.35357666015625 46.642388783472754, -48.35357666015625 47.571772, -48.35357666015625 48.49544709355706, -52.741935 48.49544709355706, -57.13165283203125 48.49544709355706, -57.13165283203125 47.571772, -57.13165283203125 46.642388783472754))" + +const locationQueryTemplate = { + operationName: null, + variables: { + locationQuery: { + pageSize: 0, + withinPolygon: "", + sortBy: "NAME" + } + }, + query: ` + query($locationQuery: LocationSearchQueryInput) { + locationList(query: $locationQuery) { + totalCount + list { + name + } + } + } + ` +} + +const reportQueryTemplate = { + operationName: null, + variables: { + reportQuery: { + pageSize: 0, + state: "PUBLISHED", + sortBy: "ENGAGEMENT_DATE", + withinPolygon: "" + } + }, + query: ` + query ($reportQuery: ReportSearchQueryInput) { + reportList(query: $reportQuery) { + totalCount + list { + location { + name + } + } + } + } + ` +} + +const positionQueryTemplate = { + operationName: null, + variables: { + positionQuery: { + pageSize: 0, + withinPolygon: "" + } + }, + query: ` + query ($positionQuery: PositionSearchQueryInput) { + positionList(query: $positionQuery) { + totalCount + list { + name + location { + name + } + } + } + } + ` +} + +describe("Location geo search, when map center is (-52.741935 47.571772)", () => { + it("should return one location for visible map bounds", async() => { + const query = lodash.cloneDeep(locationQueryTemplate) + query.variables.locationQuery.withinPolygon = polygon01 + const result = await axios.post(apiUrl, query) + expect(result?.status).to.equal(200) + + const resultList = result?.data?.data?.locationList?.list || [] + expect(resultList.length).to.equal(1) + expect(resultList[0].name).to.equal("General Hospital") + }) + + const locations01 = [ + "Cabot Tower", + "Fort Amherst", + "General Hospital", + "Murray's Hotel", + "Wishingwells Park" + ] + + it("should return 5 locations for padded (0.5) map bounds", async() => { + const query = lodash.cloneDeep(locationQueryTemplate) + query.variables.locationQuery.withinPolygon = polygon02 + const result = await axios.post(apiUrl, query) + expect(result?.status).to.equal(200) + + const resultList = result?.data?.data?.locationList?.list || [] + expect(resultList.length).to.equal(5) + expect(resultList[0].name).to.equal(locations01[0]) + expect(resultList[1].name).to.equal(locations01[1]) + expect(resultList[2].name).to.equal(locations01[2]) + expect(resultList[3].name).to.equal(locations01[3]) + expect(resultList[4].name).to.equal(locations01[4]) + }) + + it("should return 9 locations in zoom level 11 for padded (0.5) map bounds", async() => { + const query = lodash.cloneDeep(locationQueryTemplate) + query.variables.locationQuery.withinPolygon = polygon03 + const result = await axios.post(apiUrl, query) + expect(result?.status).to.equal(200) + + const resultList = result?.data?.data?.locationList?.list || [] + expect(resultList.length).to.equal(9) + expect(resultList[0].name).to.equal("Cabot Tower") + expect(resultList[1].name).to.equal("Conception Bay South Police Station") + expect(resultList[2].name).to.equal("Fort Amherst") + expect(resultList[3].name).to.equal("General Hospital") + expect(resultList[4].name).to.equal("Harbour Grace Police Station") + expect(resultList[5].name).to.equal("Murray's Hotel") + expect(resultList[6].name).to.equal("Portugal Cove Ferry Terminal") + expect(resultList[7].name).to.equal("St Johns Airport") + expect(resultList[8].name).to.equal("Wishingwells Park") + }) + + it("should return reports in only General Hospital for visible map bounds", async() => { + const query = lodash.cloneDeep(reportQueryTemplate) + query.variables.reportQuery.withinPolygon = polygon01 + const result = await axios.post(apiUrl, query) + expect(result?.status).to.equal(200) + + const resultList = result?.data?.data?.reportList?.list || [] + expect(resultList.length).to.be.gt(1) + expect( + resultList.every(r => r.location.name === "General Hospital") + ).to.equal(true) + }) + + it(`should return reports from any of "${locations01.join()}" for padded (0.5) map bounds`, async() => { + const query = lodash.cloneDeep(reportQueryTemplate) + query.variables.reportQuery.withinPolygon = polygon02 + const result = await axios.post(apiUrl, query) + expect(result?.status).to.equal(200) + + const resultList = result?.data?.data?.reportList?.list || [] + expect(resultList.length).to.be.gt(1) + resultList.forEach(r => expect(r.location.name).to.be.oneOf(locations01)) + }) + + it("shouldn't return any positions for visible map bounds", async() => { + const query = lodash.cloneDeep(positionQueryTemplate) + query.variables.positionQuery.withinPolygon = polygon01 + const result = await axios.post(apiUrl, query) + expect(result?.status).to.equal(200) + + const resultList = result?.data?.data?.positionList?.list || [] + expect(resultList.length).to.equal(0) + }) + + it("should return one position for padded map bounds", async() => { + const query = lodash.cloneDeep(positionQueryTemplate) + query.variables.positionQuery.withinPolygon = polygon02 + const result = await axios.post(apiUrl, query) + expect(result?.status).to.equal(200) + + const resultList = result?.data?.data?.positionList?.list || [] + expect(resultList.length).to.equal(1) + expect(resultList[0].name).to.equal("Planning Captain") + expect(resultList[0].location.name).to.equal("Wishingwells Park") + }) +}) diff --git a/client/yarn.lock b/client/yarn.lock index bb245e89d4..784afc487e 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -4286,6 +4286,13 @@ axe-core@^4.0.2: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.0.2.tgz#c7cf7378378a51fcd272d3c09668002a4990b1cb" integrity sha512-arU1h31OGFu+LPrOLGZ7nB45v940NMDMEJeNmbutu57P+UFDVnkZg3e+J1I2HJRZ9hT7gO8J91dn/PMrAiKakA== +axios@0.21.0: + version "0.21.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.0.tgz#26df088803a2350dff2c27f96fef99fe49442aca" + integrity sha512-fmkJBknJKoZwem3/IKSSLpkdNXZeBu5Q7GA/aRsr2btgrptmSCxi2oFjZHqGdK9DoTil9PIHlPIZw2EcRJXRvw== + dependencies: + follow-redirects "^1.10.0" + axios@^0.19.2: version "0.19.2" resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" @@ -8555,7 +8562,7 @@ follow-redirects@1.5.10: dependencies: debug "=3.1.0" -follow-redirects@^1.0.0: +follow-redirects@^1.0.0, follow-redirects@^1.10.0: version "1.13.0" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== diff --git a/insertBaseData-mssql.sql b/insertBaseData-mssql.sql index 1311aa11f1..d118b965f4 100644 --- a/insertBaseData-mssql.sql +++ b/insertBaseData-mssql.sql @@ -554,6 +554,7 @@ INSERT INTO positionRelationships (positionUuid_a, positionUuid_b, createdAt, up UPDATE positions SET locationUuid = (SELECT uuid from LOCATIONS where name = 'Kabul Police Academy') WHERE name = 'Chief of Police'; UPDATE positions SET locationUuid = (SELECT uuid from LOCATIONS where name = 'MoD Headquarters Kabul') WHERE name = 'Cost Adder - MoD'; +UPDATE positions SET locationUuid = (SELECT uuid from LOCATIONS where name = 'Wishingwells Park') WHERE name = 'Planning Captain'; --Write a couple reports! DECLARE @reportUuid varchar(36);