diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..693002a --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +#Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +release.properties +.flattened-pom.xml + +# Eclipse +.project +.classpath +.settings/ +bin/ + +# IntelliJ +.idea +*.ipr +*.iml +*.iws + +# NetBeans +nb-configuration.xml + +# Visual Studio Code +.vscode +.factorypath + +# OSX +.DS_Store + +# Vim +*.swp +*.swo + +# patch +*.orig +*.rej + +# Local environment +.env diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..f17a5eb --- /dev/null +++ b/pom.xml @@ -0,0 +1,129 @@ + + + 4.0.0 + com.c4181 + cad-call-api + 1.0.0-SNAPSHOT + + 3.10.1 + 17 + UTF-8 + UTF-8 + quarkus-bom + io.quarkus.platform + 2.16.0.Final + true + 3.0.0-M7 + + + + + ${quarkus.platform.group-id} + ${quarkus.platform.artifact-id} + ${quarkus.platform.version} + pom + import + + + + + + io.quarkus + quarkus-resteasy-reactive-jackson + + + io.quarkus + quarkus-reactive-pg-client + + + io.quarkus + quarkus-arc + + + io.quarkus + quarkus-resteasy-reactive + + + io.quarkus + quarkus-junit5 + test + + + io.rest-assured + rest-assured + test + + + + + + ${quarkus.platform.group-id} + quarkus-maven-plugin + ${quarkus.platform.version} + true + + + + build + generate-code + generate-code-tests + + + + + + maven-compiler-plugin + ${compiler-plugin.version} + + + -parameters + + + + + maven-surefire-plugin + ${surefire-plugin.version} + + + org.jboss.logmanager.LogManager + ${maven.home} + + + + + maven-failsafe-plugin + ${surefire-plugin.version} + + + + integration-test + verify + + + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + + + + + native + + + native + + + + false + native + + + + diff --git a/src/main/java/com/c4181/Controller/CallController.java b/src/main/java/com/c4181/Controller/CallController.java new file mode 100644 index 0000000..f81b96f --- /dev/null +++ b/src/main/java/com/c4181/Controller/CallController.java @@ -0,0 +1,47 @@ +package com.c4181.Controller; + +import com.c4181.model.JsoCall; +import com.c4181.model.JsoCalls; +import io.smallrye.mutiny.Multi; +import io.smallrye.mutiny.Uni; +import io.vertx.mutiny.pgclient.PgPool; +import org.jboss.resteasy.reactive.RestQuery; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.ws.rs.BadRequestException; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import java.time.LocalDateTime; + +@Path("calls") +@RequestScoped +public class CallController { + + @Inject + PgPool client; + + @Path("get-calls-in-range") + @GET + public Uni getCallsInRange(@RestQuery LocalDateTime startTime, @RestQuery LocalDateTime endTime) { + if (startTime == null || endTime == null) { + throw new BadRequestException("Start time and end time are required"); + } + + if (endTime.isBefore(startTime)) { + throw new BadRequestException("End time should be before start time"); + } + + return JsoCall.findCallsInDateRange(client, startTime, endTime); + } + + @Path("get-all-call-types") + @Produces + public Multi getAllCallTypes() { + return client.query("SELECT DISTINCT call_description FROM calls") + .execute() + .onItem().transformToMulti(set -> Multi.createFrom().iterable(set)) + .onItem().transform((row -> row.getString(0))); + } +} diff --git a/src/main/java/com/c4181/model/JsoCall.java b/src/main/java/com/c4181/model/JsoCall.java new file mode 100644 index 0000000..032f942 --- /dev/null +++ b/src/main/java/com/c4181/model/JsoCall.java @@ -0,0 +1,125 @@ +package com.c4181.model; + +import io.smallrye.mutiny.Multi; +import io.smallrye.mutiny.Uni; +import io.vertx.mutiny.pgclient.PgPool; +import io.vertx.mutiny.sqlclient.Row; +import io.vertx.mutiny.sqlclient.Tuple; + +import java.time.LocalDateTime; +import java.util.Objects; + +public class JsoCall { + + String incidentNumber; + LocalDateTime dispatchedTime; + String address; + String signal; + String callDescription; + Point point; + + public String getIncidentNumber() { + return incidentNumber; + } + + public void setIncidentNumber(String incidentNumber) { + this.incidentNumber = incidentNumber; + } + + public LocalDateTime getDispatchedTime() { + return dispatchedTime; + } + + public void setDispatchedTime(LocalDateTime dispatchedTime) { + this.dispatchedTime = dispatchedTime; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getSignal() { + return signal; + } + + public void setSignal(String signal) { + this.signal = signal; + } + + public String getCallDescription() { + return callDescription; + } + + public void setCallDescription(String callDescription) { + this.callDescription = callDescription; + } + + public Point getPoint() { + return point; + } + + public void setPoint(Point point) { + this.point = point; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + JsoCall jsoCall = (JsoCall) o; + return Objects.equals(incidentNumber, jsoCall.incidentNumber) && Objects.equals(dispatchedTime, jsoCall.dispatchedTime) && Objects.equals(address, jsoCall.address) && Objects.equals(signal, jsoCall.signal) && Objects.equals(callDescription, jsoCall.callDescription) && Objects.equals(point, jsoCall.point); + } + + @Override + public int hashCode() { + return Objects.hash(incidentNumber, dispatchedTime, address, signal, callDescription, point); + } + + @Override + public String toString() { + return "JsoCall{" + + "incidentNumber='" + incidentNumber + '\'' + + ", dispatchedTime=" + dispatchedTime + + ", address='" + address + '\'' + + ", signal='" + signal + '\'' + + ", callDescription='" + callDescription + '\'' + + ", point=" + point + + '}'; + } + + private static JsoCall fromPostgres(Row row) { + JsoCall call = new JsoCall(); + + call.setIncidentNumber(row.getString("incident_number")); + call.setDispatchedTime(row.getLocalDateTime("dispatched_time")); + call.setAddress(row.getString("address")); + call.setSignal(row.getString("signal")); + call.setCallDescription(row.getString("call_description")); + + io.vertx.pgclient.data.Point pgPoint = row.get(io.vertx.pgclient.data.Point.class, "point"); + if (pgPoint != null) { + Point point = new Point(pgPoint.getX(), pgPoint.getY()); + call.setPoint(point); + } + + return call; + } + + public static Uni findCallsInDateRange(PgPool client, LocalDateTime startTime, LocalDateTime endTime) { + JsoCalls responseObject = new JsoCalls(); + return client.preparedQuery("" + + "SELECT * " + + "FROM calls " + + "WHERE dispatched_time BETWEEN $1 AND $2").execute(Tuple.of(startTime, endTime)) + .onItem().transformToMulti(set -> Multi.createFrom().iterable(set)) + .onItem().transform(JsoCall::fromPostgres) + .collect().asList().map(jsoCalls -> { + responseObject.setCalls(jsoCalls); + return responseObject; + }); + } +} diff --git a/src/main/java/com/c4181/model/JsoCalls.java b/src/main/java/com/c4181/model/JsoCalls.java new file mode 100644 index 0000000..f968e3f --- /dev/null +++ b/src/main/java/com/c4181/model/JsoCalls.java @@ -0,0 +1,37 @@ +package com.c4181.model; + +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; + +public class JsoCalls { + List calls = new CopyOnWriteArrayList<>(); + + public List getCalls() { + return calls; + } + + public void setCalls(List calls) { + this.calls = calls; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + JsoCalls jsoCalls = (JsoCalls) o; + return Objects.equals(calls, jsoCalls.calls); + } + + @Override + public int hashCode() { + return Objects.hash(calls); + } + + @Override + public String toString() { + return "JsoCalls{" + + "calls=" + calls + + '}'; + } +} diff --git a/src/main/java/com/c4181/model/Point.java b/src/main/java/com/c4181/model/Point.java new file mode 100644 index 0000000..9340a87 --- /dev/null +++ b/src/main/java/com/c4181/model/Point.java @@ -0,0 +1,50 @@ +package com.c4181.model; + +import java.util.Objects; + +public class Point { + private double lat; + private double lng; + + public Point(double lat, double lng) { + this.lat = lat; + this.lng = lng; + } + + public double getLat() { + return lat; + } + + public void setLat(double lat) { + this.lat = lat; + } + + public double getLng() { + return lng; + } + + public void setLng(double lng) { + this.lng = lng; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Point point = (Point) o; + return Double.compare(point.lat, lat) == 0 && Double.compare(point.lng, lng) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(lat, lng); + } + + @Override + public String toString() { + return "Point{" + + "lat=" + lat + + ", lng=" + lng + + '}'; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..f1f001f --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,9 @@ +quarkus.datasource.db-kind=postgresql +quarkus.datasource.username=${USER_NAME} +quarkus.datasource.password=${PASSWORD} +quarkus.datasource.reactive.url=postgresql://192.168.1.17:5432/jsoCad + +quarkus.http.cors=true +quarkus.http.cors.origins=* +quarkus.http.cors.methods=GET +quarkus.http.cors.headers=X-Custom \ No newline at end of file