Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/dart/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## [3.1.6](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-3.1.5...dart-3.1.6) (2022-12-21)

### Bug Fixes

* Add `and`, `nor` operators in QueryBuilder ([#795](https://github.com/parse-community/Parse-SDK-Flutter/issues/795))

## [3.1.5](https://github.com/parse-community/Parse-SDK-Flutter/compare/dart-3.1.4...dart-3.1.5) (2022-12-16)

### Bug Fixes
Expand Down
2 changes: 2 additions & 0 deletions packages/dart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ QueryBuilder<ParseObject> mainQuery = QueryBuilder.or(
var apiResponse = await mainQuery.query();
```

To find objects that match several queries use __QueryBuilder.and__. To find objects that do not match any given query use __QueryBuilder.nor__.

The features available are:-
* Equals
* Contains
Expand Down
2 changes: 1 addition & 1 deletion packages/dart/lib/src/base/parse_constants.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
part of flutter_parse_sdk;

// Library
const String keySdkVersion = '3.1.5';
const String keySdkVersion = '3.1.6';
const String keyLibraryName = 'Flutter Parse SDK';

// End Points
Expand Down
14 changes: 13 additions & 1 deletion packages/dart/lib/src/network/parse_query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,19 @@ class QueryBuilder<T extends ParseObject> {
}

QueryBuilder.or(this.object, List<QueryBuilder<T>> list) {
String query = '"\$or":[';
_constructorInitializer(query: '"\$or":[', list: list);
}

QueryBuilder.and(this.object, List<QueryBuilder<T>> list) {
_constructorInitializer(query: '"\$and":[', list: list);
}

QueryBuilder.nor(this.object, List<QueryBuilder<T>> list) {
_constructorInitializer(query: '"\$nor":[', list: list);
}

void _constructorInitializer(
{required String query, required List<QueryBuilder<T>> list}) {
for (int i = 0; i < list.length; ++i) {
if (i > 0) {
query += ',';
Expand Down
2 changes: 1 addition & 1 deletion packages/dart/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: parse_server_sdk
description: Dart plugin for Parse Server, (https://parseplatform.org), (https://back4app.com)
version: 3.1.5
version: 3.1.6
homepage: https://github.com/parse-community/Parse-SDK-Flutter

environment:
Expand Down
188 changes: 188 additions & 0 deletions packages/dart/test/parse_query_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,193 @@ void main() {
'where={"\$relatedTo":{"object":{"__type":"Pointer","className":"Post","objectId":"8TOXdXf3tz"},"key":"likes"}}');
expect(result.query, expectedQuery.query);
});

test('QueryBuilder.or', () async {
final MockParseClient client = MockParseClient();

await Parse().initialize(
'appId',
'https://test.parse.com',
debug: true,
// to prevent automatic detection
fileDirectory: 'someDirectory',
// to prevent automatic detection
appName: 'appName',
// to prevent automatic detection
appPackageName: 'somePackageName',
// to prevent automatic detection
appVersion: 'someAppVersion',
);

ParseObject user = ParseObject("_User", client: client);
var firstName = QueryBuilder<ParseObject>(user)
..regEx('firstName', "Liam");

var lastName = QueryBuilder<ParseObject>(user)
..regEx('lastName', "Johnson");

QueryBuilder<ParseObject> mainQuery = QueryBuilder.or(
user,
[firstName, lastName],
);

when(client.get(
any,
options: anyNamed("options"),
onReceiveProgress: anyNamed("onReceiveProgress"),
)).thenAnswer((_) async => ParseNetworkResponse(
statusCode: 200,
data:
"{\"results\": [{\"className\": \"_User\",\"objectId\": \"fqx5BECOME\",\"createdAt\": \"2022-10-25T06:04:47.138Z\",\"updatedAt\": \"2022-10-25T06:05:22.328Z\",\"firstName\": \"Liam1\",\"lastName\": \"Johnson1\"},{\"className\": \"_User\",\"objectId\": \"hAtRRYGrUO\",\"createdAt\": \"2022-01-24T15:53:48.396Z\",\"updatedAt\": \"2022-01-25T05:52:01.701Z\",\"firstName\": \"Liam2\",\"lastName\": \"Johnson2\"}]}"));

var response = await mainQuery.query();

expect(response.results?.first, isA<ParseObject>());

ParseObject parseObject = response.results?.first;

expect(parseObject.get<String>("firstName"), "Liam1");
expect(parseObject.objectId, "fqx5BECOME");
expect(parseObject.createdAt, DateTime.parse("2022-10-25T06:04:47.138Z"));
expect(parseObject.updatedAt, DateTime.parse("2022-10-25T06:05:22.328Z"));

final Uri result = Uri.parse(verify(client.get(
captureAny,
options: anyNamed("options"),
onReceiveProgress: anyNamed("onReceiveProgress"),
)).captured.single);

expect(result.path, '/classes/_User');

final Uri expectedQuery = Uri(
query:
'where={"\$or":[{"firstName":{"\$regex":"Liam"}},{"lastName":{"\$regex":"Johnson"}}]}');
expect(result.query, expectedQuery.query);
});

test('QueryBuilder.and', () async {
final MockParseClient client = MockParseClient();

await Parse().initialize(
'appId',
'https://test.parse.com',
debug: true,
// to prevent automatic detection
fileDirectory: 'someDirectory',
// to prevent automatic detection
appName: 'appName',
// to prevent automatic detection
appPackageName: 'somePackageName',
// to prevent automatic detection
appVersion: 'someAppVersion',
);

ParseObject user = ParseObject("_User", client: client);
var firstName = QueryBuilder<ParseObject>(user)
..regEx('firstName', "jak");

var lastName = QueryBuilder<ParseObject>(user)..regEx('lastName', "jaki");

QueryBuilder<ParseObject> mainQuery = QueryBuilder.and(
user,
[firstName, lastName],
);

when(client.get(
any,
options: anyNamed("options"),
onReceiveProgress: anyNamed("onReceiveProgress"),
)).thenAnswer((_) async => ParseNetworkResponse(
statusCode: 200,
data:
"{\"results\": [{\"className\": \"_User\",\"objectId\": \"fqx5BECOME\",\"createdAt\": \"2022-10-25T06:04:47.138Z\",\"updatedAt\": \"2022-10-25T06:05:22.328Z\",\"firstName\": \"jak1\",\"lastName\": \"jaki1\"},{\"className\": \"_User\",\"objectId\": \"hAtRRYGrUO\",\"createdAt\": \"2022-01-24T15:53:48.396Z\",\"updatedAt\": \"2022-01-25T05:52:01.701Z\",\"firstName\": \"jak2\",\"lastName\": \"jaki2\"}]}"));

var response = await mainQuery.query();

expect(response.results?.first, isA<ParseObject>());

ParseObject parseObject = response.results?.first;

expect(parseObject.get<String>("firstName"), "jak1");
expect(parseObject.objectId, "fqx5BECOME");
expect(parseObject.createdAt, DateTime.parse("2022-10-25T06:04:47.138Z"));
expect(parseObject.updatedAt, DateTime.parse("2022-10-25T06:05:22.328Z"));

final Uri result = Uri.parse(verify(client.get(
captureAny,
options: anyNamed("options"),
onReceiveProgress: anyNamed("onReceiveProgress"),
)).captured.single);

expect(result.path, '/classes/_User');

final Uri expectedQuery = Uri(
query:
'where={"\$and":[{"firstName":{"\$regex":"jak"}},{"lastName":{"\$regex":"jaki"}}]}');
expect(result.query, expectedQuery.query);
});

test('QueryBuilder.nor', () async {
final MockParseClient client = MockParseClient();

await Parse().initialize(
'appId',
'https://test.parse.com',
debug: true,
// to prevent automatic detection
fileDirectory: 'someDirectory',
// to prevent automatic detection
appName: 'appName',
// to prevent automatic detection
appPackageName: 'somePackageName',
// to prevent automatic detection
appVersion: 'someAppVersion',
);

ParseObject user = ParseObject("_User", client: client);
var firstName = QueryBuilder<ParseObject>(user)
..regEx('firstName', "Oliver");

var lastName = QueryBuilder<ParseObject>(user)
..regEx('lastName', "Smith");

QueryBuilder<ParseObject> mainQuery = QueryBuilder.nor(
user,
[firstName, lastName],
);

when(client.get(
any,
options: anyNamed("options"),
onReceiveProgress: anyNamed("onReceiveProgress"),
)).thenAnswer((_) async => ParseNetworkResponse(
statusCode: 200,
data:
"{\"results\": [{\"className\": \"_User\",\"objectId\": \"fqx5BECOME\",\"createdAt\": \"2022-10-25T06:04:47.138Z\",\"updatedAt\": \"2022-10-25T06:05:22.328Z\",\"firstName\": \"Oliver1\",\"lastName\": \"Smith1\"},{\"className\": \"_User\",\"objectId\": \"hAtRRYGrUO\",\"createdAt\": \"2022-01-24T15:53:48.396Z\",\"updatedAt\": \"2022-01-25T05:52:01.701Z\",\"firstName\": \"Oliver2\",\"lastName\": \"Smith2\"}]}"));

var response = await mainQuery.query();

expect(response.results?.first, isA<ParseObject>());

ParseObject parseObject = response.results?.first;

expect(parseObject.get<String>("firstName"), "Oliver1");
expect(parseObject.objectId, "fqx5BECOME");
expect(parseObject.createdAt, DateTime.parse("2022-10-25T06:04:47.138Z"));
expect(parseObject.updatedAt, DateTime.parse("2022-10-25T06:05:22.328Z"));

final Uri result = Uri.parse(verify(client.get(
captureAny,
options: anyNamed("options"),
onReceiveProgress: anyNamed("onReceiveProgress"),
)).captured.single);

expect(result.path, '/classes/_User');

final Uri expectedQuery = Uri(
query:
'where={"\$nor":[{"firstName":{"\$regex":"Oliver"}},{"lastName":{"\$regex":"Smith"}}]}');
expect(result.query, expectedQuery.query);
});
});
}
2 changes: 2 additions & 0 deletions packages/flutter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,8 @@ QueryBuilder<ParseObject> mainQuery = QueryBuilder.or(
var apiResponse = await mainQuery.query();
```

To find objects that match several queries use __QueryBuilder.and__. To find objects that do not match any given query use __QueryBuilder.nor__.

The features available are:-
* Equals
* Contains
Expand Down