query method

Future<List<DataPoint>> query(
  1. String query
)

Query for DataPoints from the CARP backend using REST SQL (RSQL).

The query string can be build by querying data point fields using logical operations.

Query fields can be any field in a data point JSON, including nested fields. Examples include:

  • Data point fields such as id, study_id and created_at.
  • Header fields such as carp_header.start_time, carp_header.user_id, and carp_header.data_format.name
  • Body fields such as carp_body.latitude or carp_body.connectivity_status

Note that field names are nested using the dot-notation.

See here for details on grammar and semantic.

The logical operations include:

  • Logical AND : ; or and
  • Logical OR : , or or

Comparison operations include.

  • Equal to : ==
  • Not equal to : !=
  • Less than : =lt= or <
  • Less than or equal to : =le= or <=
  • Greater than operator : =gt= or >
  • Greater than or equal to : =ge= or >=
  • In : =in=
  • Not in : =out=

Examples of query strings include:

Get all data-points between 2018-05-27T13:28:07 and 2019-05-29T08:55:26

  • carp_header.created_at>2018-05-27T13:28:07Z;carp_header.created_at<2019-05-29T08:55:26Z

Get all where the user id is 1 or 2

  • carp_header.user_id==1,2

Below is an example of a data point in JSON to see the different fields.

{
  "id": 24481799,
  "study_id": 2,
  "created_by_user_id": 2,
  "created_at": "2019-06-19T09:50:44.245Z",
  "updated_at": "2019-06-19T09:50:44.245Z",
  "carp_header": {
    "study_id": "8",
    "user_id": "user@dtu.dk",
    "data_format": {
      "name": "location",
      "namepace": "carp"
    },
    "trigger_id": "task1",
    "device_role_name": "Patient's phone",
    "upload_time": "2019-06-19T09:50:43.551Z",
    "start_time": "2018-11-08T15:30:40.721748Z",
    "end_time": "2019-06-19T09:50:43.551Z"
  },
  "carp_body": {
    "altitude": 43.3,
    "device_info": {},
    "classname": "LocationDatum",
    "latitude": 23454.345,
    "accuracy": 12.4,
    "speed_accuracy": 12.3,
    "id": "3fdd1760-bd30-11e8-e209-ef7ee8358d2f",
    "speed": 2.3,
    "timestamp": "2018-11-08T15:30:40.721748Z",
    "longitude": 23.4
  }
 }

Implementation

Future<List<DataPoint>> query(String query) async {
  String url =
      (query.isEmpty) ? dataEndpointUri : "$dataEndpointUri?query=$query";

  // GET the data points from the CARP web service
  // TODO - for some reason the CARP web service don't like encoded url's....
  // http.Response response = await httpr.get(Uri.encodeFull(url), headers: restHeaders);
  http.Response response = await httpr.get(url, headers: headers);

  int httpStatusCode = response.statusCode;

  if (httpStatusCode == HttpStatus.ok) {
    List<dynamic> list = json.decode(response.body) as List<dynamic>;
    List<DataPoint> datapoints = [];
    for (var item in list) {
      datapoints.add(DataPoint.fromJson(item as Map<String, dynamic>));
    }
    return datapoints;
  }
  // All other cases are treated as an error.
  Map<String, dynamic> responseJson =
      json.decode(response.body) as Map<String, dynamic>;
  throw CarpServiceException(
    httpStatus: HTTPStatus(httpStatusCode, response.reasonPhrase),
    message: responseJson["message"].toString(),
    path: responseJson["path"].toString(),
  );
}