Skip to content

Commit a255b0a

Browse files
committed
ParseAggregate method updated, small bugs fixed
1 parent 953b54a commit a255b0a

File tree

8 files changed

+221
-96
lines changed

8 files changed

+221
-96
lines changed

packages/dart/example/main.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ Future<void> main() async {
2323
print("Response received successfully");
2424
}
2525

26-
final res = await ParseAggregate('DietPlan', pipeline: {
26+
final res = await ParseAggregate('DietPlan').execute({
2727
r'$match': {'Name': 'Ketogenic'},
2828
r'$group': {
2929
'_id': r'isHungry',
3030
'count': {r'$sum': 1}
3131
},
32-
}).execute();
32+
});
33+
34+
print('${res.statusCode}, ${res.results}');
3335

34-
print('${res.statusCode}, ${res.data}');
3536
}

packages/dart/lib/parse_server_sdk.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,13 @@ part 'src/data/parse_core_data.dart';
3333
part 'src/data/parse_subclass_handler.dart';
3434
part 'src/enums/parse_enum_api_rq.dart';
3535
part 'src/network/options.dart';
36-
part 'src/network/parse_aggregate.dart';
36+
// part 'src/network/parse_aggregate.dart';
3737
part 'src/network/parse_client.dart';
3838
part 'src/network/parse_connectivity.dart';
3939
part 'src/network/parse_live_query.dart';
4040
part 'src/network/parse_query.dart';
4141
part 'src/objects/parse_acl.dart';
42+
part 'src/objects/parse_aggregate.dart';
4243
part 'src/objects/parse_array.dart';
4344
part 'src/objects/parse_base.dart';
4445
part 'src/objects/parse_cloneable.dart';
@@ -51,6 +52,7 @@ part 'src/objects/parse_file_web.dart';
5152
part 'src/objects/parse_function.dart';
5253
part 'src/objects/parse_geo_point.dart';
5354
part 'src/objects/parse_installation.dart';
55+
part 'src/objects/parse_jobs.dart';
5456
part 'src/objects/parse_number.dart';
5557
part 'src/objects/parse_object.dart';
5658
part 'src/objects/parse_operation/parse_add_operation.dart';

packages/dart/lib/src/base/parse_constants.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ const String keyEndPointRequestPasswordReset = '/requestPasswordReset';
1616
const String keyEndPointClasses = '/classes/';
1717
const String keyEndPointHealth = '/health';
1818
const String keyEndPointAggregate = '/aggregate/';
19+
const String keyEndPointFunctions = '/functions/';
20+
const String keyEndPointJobs = '/jobs/';
1921

2022
// ParseObject variables
2123
const String keyVarClassName = 'className';

packages/dart/lib/src/network/parse_aggregate.dart

Lines changed: 0 additions & 86 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
2+
part of '../../parse_server_sdk.dart';
3+
4+
class ParseAggregate extends ParseObject {
5+
6+
ParseAggregate(
7+
this.functionName, {
8+
bool? debug,
9+
ParseClient? client,
10+
bool? autoSendSessionId,
11+
}) : super(
12+
functionName,
13+
client: client,
14+
autoSendSessionId: autoSendSessionId,
15+
debug: debug,
16+
) {
17+
_path = '$keyEndPointAggregate$functionName';
18+
}
19+
20+
final String functionName;
21+
22+
@override
23+
late String _path;
24+
25+
Future<ParseResponse> execute(Map<String, dynamic> pipeline, {Map<String, String>? headers}) async {
26+
final String uri = '${ParseCoreData().serverUrl}$_path';
27+
28+
Map<String, String> parameters = {};
29+
30+
if (pipeline.isEmpty) {
31+
throw ArgumentError(
32+
'pipeline must not be empty. Please add pipeline operations to aggregate data. '
33+
'Example: {"\$group": {"_id": "\$userId", "totalScore": {"\$sum": "\$score"}}}',
34+
);
35+
} else {
36+
parameters.addAll({
37+
'pipeline': jsonEncode(pipeline.entries.map((e) => {e.key: e.value}).toList())
38+
});
39+
_setObjectData(pipeline);
40+
}
41+
42+
try {
43+
print(Uri.parse(uri).replace(queryParameters: parameters).toString());
44+
final ParseNetworkResponse result = await _client.get(
45+
Uri.parse(uri).replace(queryParameters: parameters).toString(),
46+
options: ParseNetworkOptions(headers: headers)
47+
);
48+
return ParseResponse.fromParseNetworkResponse(result);
49+
} on Exception catch (e) {
50+
return handleException(e, ParseApiRQ.execute, _debug, parseClassName);
51+
}
52+
}
53+
}

packages/dart/lib/src/objects/parse_function.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class ParseCloudFunction extends ParseObject {
1515
autoSendSessionId: autoSendSessionId,
1616
debug: debug,
1717
) {
18-
_path = '/functions/$functionName';
18+
_path = '$keyEndPointFunctions$functionName';
1919
}
2020

2121
final String functionName;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
part of '../../parse_server_sdk.dart';
2+
3+
class ParseJobs extends ParseObject {
4+
/// Creates a new cloud function object
5+
///
6+
/// {https://docs.parseplatform.org/cloudcode/guide/}
7+
ParseJobs(
8+
this.functionName, {
9+
bool? debug,
10+
ParseClient? client,
11+
bool? autoSendSessionId,
12+
}) : super(
13+
functionName,
14+
client: client,
15+
autoSendSessionId: autoSendSessionId,
16+
debug: debug,
17+
) {
18+
_path = '$keyEndPointJobs$functionName';
19+
}
20+
21+
final String functionName;
22+
23+
@override
24+
// ignore: overridden_fields
25+
late String _path;
26+
27+
/// Executes a cloud function
28+
///
29+
/// To add the parameters, create an object and call [set](value to set)
30+
Future<ParseResponse> execute({Map<String, dynamic>? parameters, Map<String, String>? headers}) async {
31+
final String uri = '${ParseCoreData().serverUrl}$_path';
32+
if (parameters != null) {
33+
_setObjectData(parameters);
34+
}
35+
try {
36+
final ParseNetworkResponse result = await _client.post(uri, options: ParseNetworkOptions(headers: headers), data: json.encode(_getObjectData()));
37+
return handleResponse<ParseJobs>(this, result, ParseApiRQ.execute, _debug, parseClassName);
38+
} on Exception catch (e) {
39+
return handleException(e, ParseApiRQ.execute, _debug, parseClassName);
40+
}
41+
}
42+
43+
/// Executes a cloud function that returns a ParseObject type
44+
///
45+
/// To add the parameters, create an object and call [set](value to set)
46+
Future<ParseResponse> executeObjectFunction<T extends ParseObject>({Map<String, dynamic>? parameters, Map<String, String>? headers}) async {
47+
final String uri = '${ParseCoreData().serverUrl}$_path';
48+
if (parameters != null) {
49+
_setObjectData(parameters);
50+
}
51+
try {
52+
final ParseNetworkResponse result = await _client.post(uri, options: ParseNetworkOptions(headers: headers), data: json.encode(_getObjectData()));
53+
return handleResponse<T>(this, result, ParseApiRQ.executeObjectionFunction, _debug, parseClassName);
54+
} on Exception catch (e) {
55+
return handleException(e, ParseApiRQ.executeObjectionFunction, _debug, parseClassName);
56+
}
57+
}
58+
}
Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,117 @@
11
part of '../../parse_server_sdk.dart';
22

3+
/// A standardized response object returned by all Parse Server operations.
4+
///
5+
/// This class wraps the response received from the Parse Server and normalizes
6+
/// the structure so that your Dart application can easily determine:
7+
/// - whether the request was successful
8+
/// - the HTTP status code
9+
/// - the result(s) returned by the server
10+
/// - any error information
11+
///
12+
///
13+
/// ## Example usage
14+
/// ```dart
15+
/// final response = await myParseQuery.find();
16+
/// if (response.success) {
17+
/// print('Fetched ${response.count} objects.');
18+
/// for (final obj in response.results ?? []) {
19+
/// print(obj);
20+
/// }
21+
/// } else {
22+
/// print('Error: ${response.error?.message}');
23+
/// }
24+
/// ```
325
class ParseResponse {
26+
/// Creates a new [ParseResponse] instance.
27+
///
28+
/// You typically don't instantiate this directly — it's created by
29+
/// internal SDK logic, e.g. through [fromParseNetworkResponse].
430
ParseResponse({
531
this.error,
632
});
733

34+
/// Whether the request was successful.
35+
///
36+
/// This is `true` if the HTTP status code was 200 or 201.
837
bool success = false;
38+
39+
/// The HTTP status code returned by the Parse Server.
40+
///
41+
/// Defaults to -1 if not yet populated.
942
int statusCode = -1;
1043

11-
/// If result is a singular result, i.e. getByObjectID
44+
/// The direct result from the Parse Server.
1245
///
13-
/// This is now deprecated - Please use results. This will contain a list of
14-
/// results, no need to check if its a list or a list of elements anymore.
46+
/// This might be a `Map`, a `List`, or any other decoded JSON.
47+
///
48+
/// ---
49+
/// ⚠️ **Deprecated:**
50+
/// You should prefer using [results], which is guaranteed to be a list of results.
1551
dynamic result;
1652

17-
/// All results stored as a list - Even if only one response is returned
18-
// ignore: always_specify_types
53+
/// The list of results returned by the Parse Server.
54+
///
55+
/// Even if only one object is returned, it will still be inside a list.
56+
///
57+
/// This is the recommended way to access your fetched data.
1958
List? results;
59+
60+
/// The number of objects returned (i.e. `results.length`).
61+
///
62+
/// Will be 0 if there were no results.
2063
int count = 0;
64+
65+
/// If the request failed, this contains error information.
2166
ParseError? error;
67+
68+
/// Builds a [ParseResponse] from a [ParseNetworkResponse],
69+
/// typically after making an HTTP request.
70+
///
71+
/// - Decodes JSON data
72+
/// - Determines `success` based on HTTP status codes
73+
/// - Populates [results] and [count] if the response contains a list
74+
factory ParseResponse.fromParseNetworkResponse(ParseNetworkResponse response) {
75+
final ParseResponse result = ParseResponse();
76+
result.statusCode = response.statusCode;
77+
result.success = response.statusCode >= 200 && response.statusCode < 300;
78+
try {
79+
// Attempt to decode JSON data
80+
final data = jsonDecode(response.data);
81+
// Fallback if `result` was not already populated
82+
result.result ??= data;
83+
// Handle typical Parse Server response structures
84+
if (data is Map<String, dynamic>) {
85+
if (data.containsKey('results')) {
86+
final resultList = data['results'];
87+
if (resultList is List) {
88+
result.results = resultList;
89+
result.count = resultList.length;
90+
}
91+
}else if(data.containsKey('error')){
92+
result.error=ParseError(code:response.statusCode, message:data['error'].toString() );
93+
}
94+
} else if (data is List) {
95+
result.results = data;
96+
result.count = data.length;
97+
}
98+
result.results ??= [data];
99+
} catch (e,s) {
100+
result.error = ParseError(message: e.toString(),exception: Exception(s));
101+
}
102+
return result;
103+
}
104+
Map<String,dynamic> get toMap=>{
105+
'success': success,
106+
'statusCode': statusCode,
107+
// 'result': result,
108+
'results': results,
109+
'count': count,
110+
'error': error,
111+
};
112+
113+
@override
114+
String toString() {
115+
return toMap.toString();
116+
}
22117
}

0 commit comments

Comments
 (0)