From 55769bd9fe57305d76954938853edb34f7ac24fe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 01:48:18 +0000 Subject: [PATCH 1/5] Initial plan From 2cf14a4beebd883150d7b1261a045ebcceacbaf0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 01:58:04 +0000 Subject: [PATCH 2/5] Fix invalid JSON in whereMatchesQuery due to extra quotes around limiters Co-authored-by: mtrezza <5673677+mtrezza@users.noreply.github.com> --- .../dart/lib/src/network/parse_query.dart | 2 +- .../test/src/network/parse_query_test.dart | 62 ++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/packages/dart/lib/src/network/parse_query.dart b/packages/dart/lib/src/network/parse_query.dart index c2ddf8111..311bf4616 100644 --- a/packages/dart/lib/src/network/parse_query.dart +++ b/packages/dart/lib/src/network/parse_query.dart @@ -616,7 +616,7 @@ class QueryBuilder { String _buildQueryRelational(String className) { queries = _checkForMultipleColumnInstances(queries); String lim = getLimitersRelational(limiters); - return '{"where":{${buildQueries(queries)}},"className":"$className"${limiters.isNotEmpty ? ',"$lim"' : ''}}'; + return '{"where":{${buildQueries(queries)}},"className":"$className"${lim.isNotEmpty ? ',$lim' : ''}}'; } /// Builds the query relational with Key for Parse diff --git a/packages/dart/test/src/network/parse_query_test.dart b/packages/dart/test/src/network/parse_query_test.dart index 2448ee278..e18e3aedc 100644 --- a/packages/dart/test/src/network/parse_query_test.dart +++ b/packages/dart/test/src/network/parse_query_test.dart @@ -534,7 +534,67 @@ void main() { ); // assert - expect(result.query.contains("%22object2%22,%22%22include%22"), true); + expect(result.query.contains("%22object2%22,%22include%22"), true); + }); + + test('whereMatchesQuery generates valid JSON', () async { + // arrange - This test specifically checks for the bug where + // whereMatchesQuery generated invalid JSON with trailing commas + // See: https://github.com/parse-community/Parse-SDK-Flutter/issues/XXX + ParseObject deliveryArea = ParseObject("DeliveryArea"); + final deliveryAreasQuery = QueryBuilder(deliveryArea) + ..whereArrayContainsAll('postalCodes', [21075]); + + ParseObject farmer = ParseObject("Farmer", client: client); + final query = QueryBuilder(farmer) + ..whereMatchesQuery('deliveryAreas', deliveryAreasQuery) + ..whereEqualTo('isActive', true); + + var desiredOutput = {"results": []}; + + when( + client.get( + any, + options: anyNamed("options"), + onReceiveProgress: anyNamed("onReceiveProgress"), + ), + ).thenAnswer( + (_) async => ParseNetworkResponse( + statusCode: 200, + data: jsonEncode(desiredOutput), + ), + ); + + // act + await query.query(); + + final String capturedUrl = verify( + client.get( + captureAny, + options: anyNamed("options"), + onReceiveProgress: anyNamed("onReceiveProgress"), + ), + ).captured.single; + + // Extract the 'where' parameter from the URL + final Uri uri = Uri.parse(capturedUrl); + final String? whereParam = uri.queryParameters['where']; + + // assert - The JSON should be valid (no trailing commas) + expect(whereParam, isNotNull); + + // This should not throw if JSON is valid + final decoded = jsonDecode(whereParam!); + expect(decoded, isA()); + + // Verify the structure is correct + expect(decoded['deliveryAreas'], isNotNull); + expect(decoded['deliveryAreas']['\$inQuery'], isNotNull); + expect( + decoded['deliveryAreas']['\$inQuery']['className'], + 'DeliveryArea', + ); + expect(decoded['deliveryAreas']['\$inQuery']['where'], isNotNull); }); test('the result query should contains encoded special characters values', () { From 7f50e3c029a42b46daf3a12c0c6e6957512d7f87 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 01:59:16 +0000 Subject: [PATCH 3/5] Update test comment with correct issue reference #932 Co-authored-by: mtrezza <5673677+mtrezza@users.noreply.github.com> --- packages/dart/test/src/network/parse_query_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dart/test/src/network/parse_query_test.dart b/packages/dart/test/src/network/parse_query_test.dart index e18e3aedc..2e5337fde 100644 --- a/packages/dart/test/src/network/parse_query_test.dart +++ b/packages/dart/test/src/network/parse_query_test.dart @@ -540,7 +540,7 @@ void main() { test('whereMatchesQuery generates valid JSON', () async { // arrange - This test specifically checks for the bug where // whereMatchesQuery generated invalid JSON with trailing commas - // See: https://github.com/parse-community/Parse-SDK-Flutter/issues/XXX + // See: https://github.com/parse-community/Parse-SDK-Flutter/issues/932 ParseObject deliveryArea = ParseObject("DeliveryArea"); final deliveryAreasQuery = QueryBuilder(deliveryArea) ..whereArrayContainsAll('postalCodes', [21075]); From e3dbcb68811b89e4c2be111196c23b01928ad9b9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 14:34:17 +0000 Subject: [PATCH 4/5] Remove unused 'includeObject' parameter from _init method Co-authored-by: mtrezza <5673677+mtrezza@users.noreply.github.com> --- packages/dart/lib/src/utils/parse_live_list.dart | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/dart/lib/src/utils/parse_live_list.dart b/packages/dart/lib/src/utils/parse_live_list.dart index 86ad72ad3..3ea07ce1a 100644 --- a/packages/dart/lib/src/utils/parse_live_list.dart +++ b/packages/dart/lib/src/utils/parse_live_list.dart @@ -579,18 +579,14 @@ class ParseLiveElement extends ParseLiveListElement { if (includeObject != null) { queryBuilder.includeObject(includeObject); } - _init(object, loaded: loaded, includeObject: includeObject); + _init(object, loaded: loaded); } Subscription? _subscription; Map? _includes; late QueryBuilder queryBuilder; - Future _init( - T object, { - bool loaded = false, - List? includeObject, - }) async { + Future _init(T object, {bool loaded = false}) async { if (!loaded) { final ParseResponse parseResponse = await queryBuilder.query(); if (parseResponse.success) { From 60a7ff0912877360ca7751ce875234aa00967ab9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 5 Dec 2025 16:39:15 +0000 Subject: [PATCH 5/5] Add test to check for extra quotes around limiters regression Co-authored-by: mtrezza <5673677+mtrezza@users.noreply.github.com> --- .../test/src/network/parse_query_test.dart | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/packages/dart/test/src/network/parse_query_test.dart b/packages/dart/test/src/network/parse_query_test.dart index 2e5337fde..5234ae4b1 100644 --- a/packages/dart/test/src/network/parse_query_test.dart +++ b/packages/dart/test/src/network/parse_query_test.dart @@ -597,6 +597,66 @@ void main() { expect(decoded['deliveryAreas']['\$inQuery']['where'], isNotNull); }); + test('whereMatchesQuery with limiters should not have extra quotes', () async { + // arrange - This test specifically checks for the bug where limiters + // were incorrectly wrapped with extra quotes like ',"$lim"' instead of ',$lim' + // which produced patterns like ""include" (double quotes before limiter key) + // See: https://github.com/parse-community/Parse-SDK-Flutter/issues/932 + ParseObject innerObject = ParseObject("InnerClass"); + final innerQuery = QueryBuilder(innerObject) + ..includeObject(["relatedField"]) + ..whereEqualTo("status", "active"); + + ParseObject outerObject = ParseObject("OuterClass", client: client); + final outerQuery = QueryBuilder(outerObject) + ..whereMatchesQuery('innerRef', innerQuery); + + var desiredOutput = {"results": []}; + + when( + client.get( + any, + options: anyNamed("options"), + onReceiveProgress: anyNamed("onReceiveProgress"), + ), + ).thenAnswer( + (_) async => ParseNetworkResponse( + statusCode: 200, + data: jsonEncode(desiredOutput), + ), + ); + + // act + await outerQuery.query(); + + final String capturedUrl = verify( + client.get( + captureAny, + options: anyNamed("options"), + onReceiveProgress: anyNamed("onReceiveProgress"), + ), + ).captured.single; + + // assert - Check that the URL does NOT contain the buggy pattern ""include" + // (double quotes before 'include' which was caused by extra quotes around limiters) + // %22%22 is the URL-encoded form of "" (two consecutive double quotes) + expect( + capturedUrl.contains('%22%22include'), + isFalse, + reason: 'URL should not contain double quotes before limiter keys', + ); + + // Also verify the correct pattern exists: className followed by comma and include + // without extra quotes between them + // The pattern should be: "className":"InnerClass","include" not "className":"InnerClass",""include" + expect( + capturedUrl.contains('%22InnerClass%22,%22include%22'), + isTrue, + reason: + 'URL should contain properly formatted className followed by include', + ); + }); + test('the result query should contains encoded special characters values', () { // arrange final queryBuilder = QueryBuilder.name('Diet_Plans');