From 95a31c6b318855739facd9881adc2bb22750e5ff Mon Sep 17 00:00:00 2001 From: rodrigosmarques Date: Fri, 5 Apr 2019 23:48:36 -0300 Subject: [PATCH 1/5] Add Support to Relational Queries Add Support to Relational Queries --- lib/src/network/parse_query.dart | 51 ++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/src/network/parse_query.dart b/lib/src/network/parse_query.dart index d06536b07..c7dd58e85 100644 --- a/lib/src/network/parse_query.dart +++ b/lib/src/network/parse_query.dart @@ -237,6 +237,22 @@ class QueryBuilder { '\"$column\":{\"\$within\":{\"\$box\": [{\"__type\": \"GeoPoint\",\"latitude\":$latitudeS,\"longitude\":$longitudeS},{\"__type\": \"GeoPoint\",\"latitude\":$latitudeN,\"longitude\":$longitudeN}]}}')); } + // Add a constraint to the query that requires a particular key's value match another QueryBuilder + void whereMatchesQuery(String column, QueryBuilder query) { + String inQuery = query._buildQueryRelational(query.object.className); + + queries.add(MapEntry( + _SINGLE_QUERY, '\"$column\":{\"\$inQuery\":$inQuery}')); + } + + //Add a constraint to the query that requires a particular key's value does not match another QueryBuilder + void whereDoesNotMatchQuery(String column, QueryBuilder query) { + String inQuery = query._buildQueryRelational(query.object.className); + + queries.add(MapEntry( + _SINGLE_QUERY, '\"$column\":{\"\$notInQuery\":$inQuery}')); + } + /// Finishes the query and calls the server /// /// Make sure to call this after defining your queries @@ -250,6 +266,12 @@ class QueryBuilder { return 'where={${buildQueries(queries)}}${getLimiters(limiters)}'; } + /// Builds the query relational for Parse + String _buildQueryRelational(String className) { + queries = _checkForMultipleColumnInstances(queries); + return '{\"where\":{${buildQueries(queries)}},\"className\":\"$className\"${getLimitersRelational(limiters)}}'; + } + /// Runs through all queries and adds them to a query string String buildQueries(List> queries) { String queryBuilder = ''; @@ -284,17 +306,20 @@ class QueryBuilder { /// that the column and value are being queried against MapEntry _buildQueryWithColumnValueAndOperator( MapEntry columnAndValue, String queryOperator) { - final String key = columnAndValue.key; - final dynamic value = convertValueToCorrectType(parseEncode(columnAndValue.value)); + final dynamic value = + convertValueToCorrectType(parseEncode(columnAndValue.value)); if (queryOperator == _NO_OPERATOR_NEEDED) { - return MapEntry(_NO_OPERATOR_NEEDED, '\"$key\": ${jsonEncode(value)}'); + return MapEntry( + _NO_OPERATOR_NEEDED, '\"$key\": ${jsonEncode(value)}'); } else { String queryString = '\"$key\":'; - final Map queryOperatorAndValueMap = Map(); + final Map queryOperatorAndValueMap = + Map(); queryOperatorAndValueMap[queryOperator] = parseEncode(value); - final String formattedQueryOperatorAndValue = jsonEncode(queryOperatorAndValueMap); + final String formattedQueryOperatorAndValue = + jsonEncode(queryOperatorAndValueMap); queryString += '$formattedQueryOperatorAndValue'; return MapEntry(key, queryString); } @@ -336,7 +361,8 @@ class QueryBuilder { for (MapEntry queryToCompact in listOfQueriesCompact) { var queryToCompactValue = queryToCompact.value.toString(); queryToCompactValue = queryToCompactValue.replaceFirst("{", ""); - queryToCompactValue = queryToCompactValue.replaceRange(queryToCompactValue.length - 1, queryToCompactValue.length, ""); + queryToCompactValue = queryToCompactValue.replaceRange( + queryToCompactValue.length - 1, queryToCompactValue.length, ""); if (listOfQueriesCompact.first == queryToCompact) { queryEnd += queryToCompactValue.replaceAll(queryStart, ' '); } else { @@ -364,4 +390,17 @@ class QueryBuilder { }); return result; } + + /// Adds the limiters to the query relational, i.e. skip=10, limit=10 + String getLimitersRelational(Map map) { + String result = ''; + map.forEach((String key, dynamic value) { + if (result != null) { + result = result + ',\"$key":$value'; + } else { + result = '\"$key\":$value'; + } + }); + return result; + } } From 50a6ef9075b956b062efba2dadcc41683f65ffee Mon Sep 17 00:00:00 2001 From: rodrigosmarques Date: Sat, 6 Apr 2019 01:50:03 -0300 Subject: [PATCH 2/5] Add Support to Counting Objects Add Support to Counting Objects https://docs.parseplatform.org/rest/guide/#counting-objects --- lib/src/network/parse_query.dart | 11 +++++++++++ lib/src/objects/response/parse_response_builder.dart | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/lib/src/network/parse_query.dart b/lib/src/network/parse_query.dart index c7dd58e85..d32a5c1ea 100644 --- a/lib/src/network/parse_query.dart +++ b/lib/src/network/parse_query.dart @@ -260,6 +260,11 @@ class QueryBuilder { return object.query(_buildQuery()); } + ///Counts the number of objects that match this query + Future count() async { + return object.query(_buildQueryCount()); + } + /// Builds the query for Parse String _buildQuery() { queries = _checkForMultipleColumnInstances(queries); @@ -272,6 +277,12 @@ class QueryBuilder { return '{\"where\":{${buildQueries(queries)}},\"className\":\"$className\"${getLimitersRelational(limiters)}}'; } + /// Builds the query for Parse + String _buildQueryCount() { + queries = _checkForMultipleColumnInstances(queries); + return 'where={${buildQueries(queries)}}&count=1'; + } + /// Runs through all queries and adds them to a query string String buildQueries(List> queries) { String queryBuilder = ''; diff --git a/lib/src/objects/response/parse_response_builder.dart b/lib/src/objects/response/parse_response_builder.dart index 74075ca03..b7e06767b 100644 --- a/lib/src/objects/response/parse_response_builder.dart +++ b/lib/src/objects/response/parse_response_builder.dart @@ -71,6 +71,11 @@ class _ParseResponseBuilder { response.results = items; response.result = items; response.count = items.length; + } else if (map != null && map.length == 2 && map.containsKey('count')) { + final List results = [map['count']]; + response.results = results; + response.result = results; + response.count = map['count']; } else { final T item = _handleSingleResult(object, map, false); response.count = 1; From 086e036fe68ed682e2deab5526a6b7f3ba059b75 Mon Sep 17 00:00:00 2001 From: Rodrigo de Souza Marques Date: Sat, 6 Apr 2019 09:02:21 -0300 Subject: [PATCH 3/5] Update README.md Update documentation with example for Relational Queries and Counting Objects --- README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/README.md b/README.md index 37f1b35c6..37c1cc601 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,54 @@ The features available are:- * Ascending * Descending * Plenty more! + +## Relational queries +If you want to retrieve objects where a field contains an object that matches another query, you can use the +__whereMatchesQuery__ condition. +For example, imagine you vave Post class and a Comment class, where each Comment has a pointer to its parent Post. +You can find comments on posts with images by doing: + +```dart + QueryBuilder queryPost = + QueryBuilder(ParseObject('Post')) + ..whereValueExists('image', true); + + QueryBuilder queryComment = + QueryBuilder(ParseObject('Comment')) + ..whereMatchesQuery('post', queryPost); + + var apiResponse = await queryComment.query(); +``` + +If you want to retrieve objects where a field contains an object that does not match another query, you can use the +__whereDoesNotMatchQuery__ condition. +Imagine you have Post class and a Comment class, where each Comment has a pointer to its parent Post. +You can find comments on posts without images by doing: + +```dart + QueryBuilder queryPost = + QueryBuilder(ParseObject('Post')) + ..whereValueExists('image', true); + + QueryBuilder queryComment = + QueryBuilder(ParseObject('Comment')) + ..whereDoesNotMatchQuery('post', queryPost); + + var apiResponse = await queryComment.query(); +``` + +## Counting Objects +If you only care about the number of games played by a particular player: + +```dart + QueryBuilder queryPlayers = + QueryBuilder(ParseObject('GameScore')) + ..whereEqualTo('playerName', 'Jonathan Walsh'); + var apiResponse = await queryPlayers.count(); + if (apiResponse.success && apiResponse.result != null) { + int countPlayers = apiResponse.count; + } +``` ## Objects From 319030a69b4261759f8cbb705c372f52180986f9 Mon Sep 17 00:00:00 2001 From: Rodrigo de Souza Marques Date: Sat, 6 Apr 2019 09:03:14 -0300 Subject: [PATCH 4/5] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 37c1cc601..157a13d12 100644 --- a/README.md +++ b/README.md @@ -151,7 +151,7 @@ If you only care about the number of games played by a particular player: ..whereEqualTo('playerName', 'Jonathan Walsh'); var apiResponse = await queryPlayers.count(); if (apiResponse.success && apiResponse.result != null) { - int countPlayers = apiResponse.count; + int countGames = apiResponse.count; } ``` From 8a8234bc2d0d3f2f6d7a918fcc2e916a31f7b04d Mon Sep 17 00:00:00 2001 From: Rodrigo de Souza Marques Date: Sat, 6 Apr 2019 11:15:41 -0300 Subject: [PATCH 5/5] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 157a13d12..aeaefdc27 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ The features available are:- ## Relational queries If you want to retrieve objects where a field contains an object that matches another query, you can use the __whereMatchesQuery__ condition. -For example, imagine you vave Post class and a Comment class, where each Comment has a pointer to its parent Post. +For example, imagine you have Post class and a Comment class, where each Comment has a pointer to its parent Post. You can find comments on posts with images by doing: ```dart