diff --git a/ilp-cw-api/[POST] query/GT LT -contradict.bru b/ilp-cw-api/[POST] query/GT LT -contradict.bru new file mode 100644 index 0000000..263905e --- /dev/null +++ b/ilp-cw-api/[POST] query/GT LT -contradict.bru @@ -0,0 +1,44 @@ +meta { + name: GT LT -contradict + type: http + seq: 3 +} + +post { + url: {{API_BASE}}/query + body: json + auth: inherit +} + +body:json { + [ + { + "attribute": "capacity", + "operator": ">", + "value": "8" + }, + { + "attribute": "capacity", + "operator": "<", + "value": "8" + } + ] +} + +assert { + res.status: eq 200 + res.body: length 0 +} + +tests { + test("Response body is a JSON array", function() { + expect(res.getBody()).to.be.an('array'); + }); + + +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[POST] query/GT LT EQ.bru b/ilp-cw-api/[POST] query/GT LT EQ.bru new file mode 100644 index 0000000..a86be2d --- /dev/null +++ b/ilp-cw-api/[POST] query/GT LT EQ.bru @@ -0,0 +1,53 @@ +meta { + name: GT LT EQ + type: http + seq: 4 +} + +post { + url: {{API_BASE}}/query + body: json + auth: inherit +} + +body:json { + [ + { + "attribute": "capacity", + "operator": ">", + "value": "8" + }, + { + "attribute": "maxMoves", + "operator": "<", + "value": "2000" + }, + { + "attribute": "cooling", + "operator": "=", + "value": "true" + } + ] +} + +assert { + res.status: eq 200 + res.body: length 1 +} + +tests { + test("Response body is a JSON array", function() { + expect(res.getBody()).to.be.an('array'); + }); + + test("Array is not empty and contains Strings", function() { + const data = res.getBody(); + expect(data[0]).to.be.a('string'); // data should be in string + }); + +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[POST] query/GT LT.bru b/ilp-cw-api/[POST] query/GT LT.bru new file mode 100644 index 0000000..19d057d --- /dev/null +++ b/ilp-cw-api/[POST] query/GT LT.bru @@ -0,0 +1,48 @@ +meta { + name: GT LT + type: http + seq: 2 +} + +post { + url: {{API_BASE}}/query + body: json + auth: inherit +} + +body:json { + [ + { + "attribute": "capacity", + "operator": ">", + "value": "8" + }, + { + "attribute": "maxMoves", + "operator": "<", + "value": "2000" + } + ] +} + +assert { + res.status: eq 200 + res.body: length 2 +} + +tests { + test("Response body is a JSON array", function() { + expect(res.getBody()).to.be.an('array'); + }); + + test("Array is not empty and contains Strings", function() { + const data = res.getBody(); + expect(data[0]).to.be.a('string'); // data should be in string + }); + +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/ilp-cw-api/[POST] query/folder.bru b/ilp-cw-api/[POST] query/folder.bru new file mode 100644 index 0000000..9f6a596 --- /dev/null +++ b/ilp-cw-api/[POST] query/folder.bru @@ -0,0 +1,8 @@ +meta { + name: [POST] query + seq: 4 +} + +auth { + mode: inherit +} diff --git a/ilp-cw-api/[POST] query/three eqs.bru b/ilp-cw-api/[POST] query/three eqs.bru new file mode 100644 index 0000000..b59ead6 --- /dev/null +++ b/ilp-cw-api/[POST] query/three eqs.bru @@ -0,0 +1,53 @@ +meta { + name: three eqs + type: http + seq: 1 +} + +post { + url: {{API_BASE}}/query + body: json + auth: inherit +} + +body:json { + [ + { + "attribute": "capacity", + "operator": "=", + "value": "20" + }, + { + "attribute": "heating", + "operator": "=", + "value": "false" + }, + { + "attribute": "cooling", + "operator": "=", + "value": "true" + } + ] +} + +assert { + res.status: eq 200 + res.body: length 1 +} + +tests { + test("Response body is a JSON array", function() { + expect(res.getBody()).to.be.an('array'); + }); + + test("Array is not empty and contains Strings", function() { + const data = res.getBody(); + expect(data[0]).to.be.a('string'); // data should be in string + }); + +} + +settings { + encodeUrl: true + timeout: 0 +} diff --git a/src/main/java/io/github/js0ny/ilp_coursework/data/AttrComparatorDto.java b/src/main/java/io/github/js0ny/ilp_coursework/data/AttrComparatorDto.java index 743e46c..478a570 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/data/AttrComparatorDto.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/data/AttrComparatorDto.java @@ -1,4 +1,7 @@ package io.github.js0ny.ilp_coursework.data; +// TODO: Convert operator to Enum +// import io.github.js0ny.ilp_coursework.util.AttrOperator; + public record AttrComparatorDto(String attribute, String operator, String value) { } diff --git a/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java b/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java index d31d723..99508d5 100644 --- a/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java +++ b/src/main/java/io/github/js0ny/ilp_coursework/service/DroneInfoService.java @@ -4,6 +4,8 @@ import io.github.js0ny.ilp_coursework.data.AttrComparatorDto; import io.github.js0ny.ilp_coursework.data.DroneDto; import io.github.js0ny.ilp_coursework.util.AttrOperator; +import static io.github.js0ny.ilp_coursework.util.AttrComparator.isValueMatched; + import java.net.URI; import java.util.Arrays; import java.util.HashSet; @@ -41,10 +43,13 @@ public class DroneInfoService { /** * Return an array of ids of drones with/without cooling capability + *
+ * Associated service method with {@code /dronesWithCooling/{state}} * * @param state determines the capability filtering * @return if {@code state} is true, return ids of drones with cooling - * capability, else without cooling + * capability, else without cooling + * @see io.github.js0ny.ilp_coursework.controller.DroneController#getDronesWithCoolingCapability(boolean) */ public String[] dronesWithCooling(boolean state) { URI droneUrl = URI.create(baseUrl).resolve(dronesEndpoint); @@ -53,7 +58,7 @@ public class DroneInfoService { DroneDto[].class); if (drones == null) { - return new String[] {}; + return new String[]{}; } return Arrays.stream(drones) @@ -64,6 +69,8 @@ public class DroneInfoService { /** * Return a {@link DroneDto}-style json data structure with the given {@code id} + *
+ * Associated service method with {@code /droneDetails/{id}} * * @param id The id of the drone * @return drone json body of given id @@ -72,6 +79,7 @@ public class DroneInfoService { * @throws IllegalArgumentException when drone with given {@code id} cannot be * found * this should lead to a 404 + * @see io.github.js0ny.ilp_coursework.controller.DroneController#getDroneDetail(String) */ public DroneDto droneDetail(String id) { URI droneUrl = URI.create(baseUrl).resolve(dronesEndpoint); @@ -89,30 +97,68 @@ public class DroneInfoService { } } + // This will result in 404 throw new IllegalArgumentException( "drone with that ID cannot be found"); } /** - * Return an array of ids of drones with a given attribute name and value + * Return an array of ids of drones with a given attribute name and value. + *
+ * Associated service method with {@code /queryAsPath/{attrName}/{attrVal}}
*
* @param attrName the attribute name to filter on
* @param attrVal the attribute value to filter on
* @return array of drone ids matching the attribute name and value
+ * @see #dronesWithAttributeCompared(String, String, AttrOperator)
+ * @see io.github.js0ny.ilp_coursework.controller.DroneController#getIdByAttrMap
*/
public String[] dronesWithAttribute(String attrName, String attrVal) {
// Call the helper with EQ operator
return dronesWithAttributeCompared(attrName, attrVal, AttrOperator.EQ);
}
+ /**
+ * Return an array of ids of drones which matches all given complex comparing rules
+ *
+ * @param attrComparators The filter rule with Name, Value and Operator
+ * @return array of drone ids that matches all rules
+ */
+ public String[] dronesSatisfyingAttributes(AttrComparatorDto[] attrComparators) {
+ Set
+ * This method act as a concatenation of
+ * {@link io.github.js0ny.ilp_coursework.util.AttrComparator#isValueMatched(JsonNode, String,
+ * AttrOperator)}
*
* @param attrName the attribute name to filter on
* @param attrVal the attribute value to filter on
* @param op the comparison operator
* @return array of drone ids matching the attribute name and value (filtered by
- * {@code op})
+ * {@code op})
+ * @see io.github.js0ny.ilp_coursework.util.AttrComparator#isValueMatched(JsonNode,
+ * String,
+ * AttrOperator)
*/
private String[] dronesWithAttributeCompared(String attrName, String attrVal, AttrOperator op) {
URI droneUrl = URI.create(baseUrl).resolve(dronesEndpoint);
@@ -122,7 +168,7 @@ public class DroneInfoService {
DroneDto[].class);
if (drones == null) {
- return new String[] {};
+ return new String[]{};
}
// Use Jackson's ObjectMapper to convert DroneDto to JsonNode for dynamic
@@ -144,49 +190,7 @@ public class DroneInfoService {
.toArray(String[]::new);
}
- // TODO: Implement this
- public String[] dronesSatisfyingAttributes(AttrComparatorDto[] attrComparators) {
- Set