Querying devices with RQL

October 2nd, 2020


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.

Copyright © 2020 Radix IoT, LLC.