This is the 5th article of a Build Java Module for Mango series. You can check all the articles by clicking here
In our use case, it would be nice to have a way to search for devices which match certain conditions. For example, all the devices with the model equals to ABC
and with the protocol equals to MODBUS
.
To make this kind of queries, Mango uses RQL (Resource Query Language), it is a textual query syntax that is similar to SQL. It describes the set of conditions that must be matched by items of a particular item descriptor.
For example, we can make a RQL query from the example above like this:
/rest/latest/enmet-devices?eq(model,ABC)&eq(protocol,MODBUS)
So, let’s add the new endpoint in our DeviceRestController
:
@Api(value = "Energy Metering Devices")
@RestController()
@RequestMapping("/enmet-devices")
public class DeviceRestController {
// ...more code...
@ApiOperation(
value = "Query devices",
notes = "Use RQL formatted query",
response = DeviceModel.class,
responseContainer = "List"
)
@RequestMapping(method = RequestMethod.GET)
public StreamedArrayWithTotal queryRQL(HttpServletRequest request, @AuthenticationPrincipal User user) {
ASTNode rql = RQLUtils.parseRQLtoAST(request.getQueryString());
return this.doQuery(rql, user);
}
// ...more code...
protected StreamedArrayWithTotal doQuery(ASTNode rql, User user) {
return new StreamedVORqlQueryWithTotal<>(
this.service,
rql,
null,
null,
null,
(item) -> this.mapping.map(item, user, mapper)
);
}
}
We parse the RQL query to an ASTNode object representing the root node of an Abstract Syntax Tree (AST). Then, the actually do the query, and we return a response like this:
{
data: {
items: [...],
$total: 12
}
}
Now we can add a new test to our device.spec.js
:
it('should query devices with RQL', () => {
const device = newDevice();
return client.restRequest({
path: '/rest/latest/enmet-devices',
method: 'POST',
data: device
}).then(response => {
assertDevice(response.data, device);
return client.restRequest({
path: `/rest/latest/enmet-devices?eq(xid,${device.xid})`,
method: 'GET'
}).then(response => {
assert.equal(response.data.items.length, 1);
assertDevice(response.data.items[0], device);
});
}).finally(() => {
return client.restRequest({
path: `/rest/latest/enmet-devices/${device.xid}`,
method: 'DELETE'
});
})
});
And we are done! Now you can query or filter devices by the condition that you want. Check this to know more about RQL
.