Skip to content

Commit b4c130d

Browse files
authored
Firestore Aggregate Count Implementation and Tests (#659)
* AggregateQuery count implementation and tests * Implement AggregateQuery Count with tests * Add comments and prune imports * Fix comments
1 parent c18fc44 commit b4c130d

File tree

13 files changed

+336
-1
lines changed

13 files changed

+336
-1
lines changed

docs/readme.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ Release Notes
7878
as a Java file instead of precompiling it. This is to better support
7979
changes with the UnityPlayerActivity, and GameActivity options, in
8080
the Unity 2023 editor.
81+
- Firestore: Added `Query.Count()`, which fetches the number of documents in
82+
the result set without actually downloading the documents
83+
([#659](https://github.com/firebase/firebase-unity-sdk/pull/659)).
8184

8285
### 10.6.0
8386
- Changes

firestore/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ set(firebase_firestore_swig
2323

2424
# Firebase Firestore CSharp files that should be included in reference docs
2525
set(firebase_firestore_src_documented
26+
src/AggregateQuery.cs
27+
src/AggregateQuerySnapshot.cs
28+
src/AggregateSource.cs
2629
src/Blob.cs
2730
src/CollectionReference.cs
2831
src/DocumentChange.cs

firestore/src/AggregateQuery.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
2+
3+
using Firebase.Firestore.Internal;
4+
using System.Threading.Tasks;
5+
6+
namespace Firebase.Firestore {
7+
/// <summary>
8+
/// A query that calculates aggregations over an underlying query.
9+
/// </summary>
10+
public sealed class AggregateQuery
11+
{
12+
private readonly AggregateQueryProxy _proxy;
13+
private readonly FirebaseFirestore _firestore;
14+
15+
internal AggregateQuery(AggregateQueryProxy proxy, FirebaseFirestore firestore) {
16+
_proxy = Util.NotNull(proxy);
17+
_firestore = Util.NotNull(firestore);
18+
}
19+
20+
/// <summary>
21+
/// The query of aggregations that will be calculated.
22+
/// </summary>
23+
public Query Query => new Query(_proxy.query(), _firestore);
24+
25+
/// <summary>
26+
/// Asynchronously executes the query.
27+
/// </summary>
28+
/// <param name="source">The source from which to acquire the aggregate results.</param>
29+
/// <returns>The results of the query.</returns>
30+
public Task<AggregateQuerySnapshot> GetSnapshotAsync(AggregateSource source) {
31+
var sourceProxy = Enums.Convert(source);
32+
return Util.MapResult(_proxy.GetAsync(sourceProxy),
33+
taskResult => { return new AggregateQuerySnapshot(taskResult, _firestore); });
34+
}
35+
36+
/// <inheritdoc />
37+
public override bool Equals(object obj) => Equals(obj as Query);
38+
39+
/// <summary>
40+
/// Compares this aggregate query with another for equality.
41+
/// </summary>
42+
/// <param name="other">The aggregate query to compare this one with.</param>
43+
/// <returns><c>true</c> if this aggregate query is equal to <paramref name="other"/>;
44+
/// <c>false</c> otherwise.</returns>
45+
public bool Equals(AggregateQuery other) => other != null && FirestoreCpp.AggregateQueryEquals(_proxy, other._proxy);
46+
47+
/// <inheritdoc />
48+
public override int GetHashCode() {
49+
return FirestoreCpp.AggregateQueryHashCode(_proxy);
50+
}
51+
}
52+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2017 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using Firebase.Firestore.Internal;
16+
17+
namespace Firebase.Firestore {
18+
/// <summary>
19+
/// The results of executing an <c>AggregateQuerySnapshot</c>.
20+
/// </summary>
21+
public sealed class AggregateQuerySnapshot {
22+
private readonly AggregateQuerySnapshotProxy _proxy;
23+
private readonly FirebaseFirestore _firestore;
24+
25+
internal AggregateQuerySnapshot(AggregateQuerySnapshotProxy proxy, FirebaseFirestore firestore) {
26+
_proxy = Util.NotNull(proxy);
27+
_firestore = Util.NotNull(firestore);
28+
}
29+
/// <summary>
30+
/// Returns the query that was executed to produce this result.
31+
/// </summary>
32+
public AggregateQuery Query {
33+
get {
34+
return new AggregateQuery(_proxy.query(), _firestore);
35+
}
36+
}
37+
38+
/// <summary>
39+
/// Returns the number of documents in the result set of the underlying query.
40+
/// </summary>
41+
public long Count {
42+
get {
43+
return _proxy.count();
44+
}
45+
}
46+
47+
/// <inheritdoc />
48+
public override bool Equals(object obj) => Equals(obj as AggregateQuerySnapshot);
49+
50+
/// <summary>
51+
/// Compares this aggregate snapshot with another for equality.
52+
/// </summary>
53+
/// <param name="other">The aggregate snapshot to compare this one with.</param>
54+
/// <returns><c>true</c> if this aggregate snapshot is equal to <paramref name="other"/>;
55+
/// <c>false</c> otherwise.</returns>
56+
public bool Equals(AggregateQuerySnapshot other) =>
57+
other != null && FirestoreCpp.AggregateQuerySnapshotEquals(_proxy, other._proxy);
58+
59+
/// <inheritdoc />
60+
public override int GetHashCode() {
61+
return FirestoreCpp.AggregateQuerySnapshotHashCode(_proxy);
62+
}
63+
}
64+
}

firestore/src/AggregateSource.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2023 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace Firebase.Firestore {
16+
17+
/// <summary>
18+
/// The sources from which an <see cref="AggregateQuery.GetSnapshotAsync"/> can retrieve its
19+
/// results.
20+
/// </summary>
21+
public enum AggregateSource {
22+
/// Perform the aggregation on the server and download the result.
23+
/// The result received from the server is presented, unaltered, without
24+
/// considering any local state. That is, documents in the local cache are not
25+
/// taken into consideration, neither are local modifications not yet
26+
/// synchronized with the server. Previously-downloaded results, if any, are
27+
/// not used: every request using this source necessarily involves a round trip
28+
/// to the server.
29+
///
30+
/// The AggregateQuery will fail if the server cannot be reached, such as if
31+
/// the client is offline.
32+
Server,
33+
}
34+
35+
}

firestore/src/Query.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,27 @@ public FirebaseFirestore Firestore {
5353
}
5454
}
5555

56+
/// <summary>
57+
/// Returns a query that counts the documents in the result set of this query.
58+
///
59+
/// The returned query, when executed, counts the documents in the result set
60+
/// of this query without actually downloading the documents.
61+
///
62+
/// Using the returned query to count the documents is efficient because only
63+
/// the final count, not the documents' data, is downloaded. The returned query
64+
/// can even count the documents if the result set would be prohibitively large
65+
/// to download entirely (e.g. thousands of documents).
66+
/// </summary>
67+
/// <returns>
68+
/// An aggregate query that counts the documents in the result set of this query.
69+
/// </returns>
70+
public AggregateQuery Count {
71+
get {
72+
return new AggregateQuery(_proxy.Count(), _firestore);
73+
}
74+
}
75+
76+
5677
/// <summary>
5778
/// Creates and returns a new <c>Query</c> with the additional filter that documents must
5879
/// contain the specified field and the value should be equal to the specified value.

firestore/src/internal/Enums.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ namespace Firebase.Firestore.Internal {
1919
/// documentation purposes -- they are otherwise equivalent to the proxy ones.
2020
static class Enums {
2121

22+
public static AggregateSourceProxy Convert(AggregateSource aggregateSource) {
23+
switch (aggregateSource) {
24+
case AggregateSource.Server:
25+
return AggregateSourceProxy.Server;
26+
default:
27+
throw new System.ArgumentOutOfRangeException("Unexpected enum value: " +
28+
aggregateSource.ToString());
29+
}
30+
}
2231
public static SourceProxy Convert(Source source) {
2332
switch (source) {
2433
case Source.Default:

firestore/src/swig/equality_compare.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ namespace firebase {
1313
namespace firestore {
1414
namespace csharp {
1515

16+
bool AggregateQueryEquals(const AggregateQuery* lhs, const AggregateQuery* rhs) {
17+
return EqualityCompareHelper(lhs, rhs);
18+
}
19+
20+
bool AggregateQuerySnapshotEquals(const AggregateQuerySnapshot* lhs, const AggregateQuerySnapshot* rhs) {
21+
return EqualityCompareHelper(lhs, rhs);
22+
}
23+
1624
bool QueryEquals(const Query* lhs, const Query* rhs) {
1725
return EqualityCompareHelper(lhs, rhs);
1826
}

firestore/src/swig/equality_compare.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef FIREBASE_FIRESTORE_CLIENT_UNITY_SRC_SWIG_EQUALITY_COMPARE_H_
22
#define FIREBASE_FIRESTORE_CLIENT_UNITY_SRC_SWIG_EQUALITY_COMPARE_H_
33

4+
#include "firestore/src/include/firebase/firestore/aggregate_query.h"
5+
#include "firestore/src/include/firebase/firestore/aggregate_query_snapshot.h"
46
#include "firestore/src/include/firebase/firestore/document_change.h"
57
#include "firestore/src/include/firebase/firestore/document_snapshot.h"
68
#include "firestore/src/include/firebase/firestore/query.h"
@@ -10,7 +12,15 @@ namespace firebase {
1012
namespace firestore {
1113
namespace csharp {
1214

13-
// Compares two `Query` objects for equality using their `==` operator, handling
15+
// Compares two `AggregateQuery` objects for equality using their `==` operator, handling
16+
// one or both of them being `nullptr`.
17+
bool AggregateQueryEquals(const AggregateQuery* lhs, const AggregateQuery* rhs);
18+
19+
// Compares two `AggregateQuerySnapshot` objects for equality using their `==` operator,
20+
// handling one or both of them being `nullptr`.
21+
bool AggregateQuerySnapshotEquals(const AggregateQuerySnapshot* lhs, const AggregateQuerySnapshot* rhs);
22+
23+
// Compares two `Query` objects for equality using their `==` operator, handling
1424
// one or both of them being `nullptr`.
1525
bool QueryEquals(const Query* lhs, const Query* rhs);
1626

firestore/src/swig/firestore.i

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ SWIG_MAP_CFUNC_TO_CSDELEGATE(::firebase::firestore::csharp::LoadBundleTaskProgre
201201

202202
// Generate Future instantiations, must be before other wrappers.
203203
%include "app/src/swig/future.i"
204+
%SWIG_FUTURE(Future_AggregateQuerySnapshot, AggregateQuerySnapshotProxy, internal,
205+
firebase::firestore::AggregateQuerySnapshot, FirestoreException)
204206
%SWIG_FUTURE(Future_QuerySnapshot, QuerySnapshotProxy, internal,
205207
firebase::firestore::QuerySnapshot, FirestoreException)
206208
%SWIG_FUTURE(Future_DocumentSnapshot, DocumentSnapshotProxy, internal,
@@ -250,6 +252,10 @@ SWIG_CREATE_PROXY(firebase::firestore::ListenerRegistration)
250252
SWIG_CREATE_PROXY(firebase::firestore::Source)
251253
%include "firestore/src/include/firebase/firestore/source.h"
252254
255+
// Generate a C# wrapper for Source. Must be before AggregateQuery.
256+
SWIG_CREATE_PROXY(firebase::firestore::AggregateSource)
257+
%include "firestore/src/include/firebase/firestore/aggregate_source.h"
258+
253259
// Generate a C# wrapper for FieldPath. Must be above DocumentSnapshot and SetOptions.
254260
SWIG_CREATE_PROXY(firebase::firestore::FieldPath)
255261
%rename("%s") firebase::firestore::FieldPath::FieldPath(const std::vector<std::string>&);
@@ -369,6 +375,7 @@ SWIG_CREATE_PROXY(firebase::firestore::Query);
369375
%rename("%s") firebase::firestore::Query::EndBefore(const DocumentSnapshot&) const;
370376
%rename("%s") firebase::firestore::Query::EndAt(const DocumentSnapshot&) const;
371377
%rename("%s") firebase::firestore::Query::Get;
378+
%rename("%s") firebase::firestore::Query::Count;
372379
%rename("%s") firebase::firestore::Query::Direction;
373380
%include "firestore/src/include/firebase/firestore/query.h"
374381
@@ -387,6 +394,18 @@ SWIG_CREATE_PROXY(firebase::firestore::QuerySnapshot);
387394
%rename("%s") firebase::firestore::QuerySnapshot::size;
388395
%include "firestore/src/include/firebase/firestore/query_snapshot.h"
389396
397+
// Generate a C# wrapper for AggregateQuery. Must be after Query.
398+
SWIG_CREATE_PROXY(firebase::firestore::AggregateQuery);
399+
%rename("%s") firebase::firestore::AggregateQuery::query;
400+
%rename("%s") firebase::firestore::AggregateQuery::Get;
401+
%include "firestore/src/include/firebase/firestore/aggregate_query.h"
402+
403+
// Generate a C# wrapper for AggregateQuerySnapshot. Must be after AggregateQuery.
404+
SWIG_CREATE_PROXY(firebase::firestore::AggregateQuerySnapshot);
405+
%rename("%s") firebase::firestore::AggregateQuerySnapshot::query;
406+
%rename("%s") firebase::firestore::AggregateQuerySnapshot::count;
407+
%include "firestore/src/include/firebase/firestore/aggregate_query_snapshot.h"
408+
390409
// Generate a C# wrapper for Settings.
391410
SWIG_CREATE_PROXY(firebase::firestore::Settings);
392411
%rename("%s") firebase::firestore::Settings::kCacheSizeUnlimited;

0 commit comments

Comments
 (0)