Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firestore Aggregate Count Implementation and Tests #659

Merged
merged 5 commits into from
Apr 6, 2023
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
3 changes: 3 additions & 0 deletions docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ Release Notes
as a Java file instead of precompiling it. This is to better support
changes with the UnityPlayerActivity, and GameActivity options, in
the Unity 2023 editor.
- Firestore: Added `Query.Count()`, which fetches the number of documents in
the result set without actually downloading the documents
([#659](https://github.com/firebase/firebase-unity-sdk/pull/659)).

### 10.6.0
- Changes
Expand Down
3 changes: 3 additions & 0 deletions firestore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ set(firebase_firestore_swig

# Firebase Firestore CSharp files that should be included in reference docs
set(firebase_firestore_src_documented
src/AggregateQuery.cs
src/AggregateQuerySnapshot.cs
src/AggregateSource.cs
src/Blob.cs
src/CollectionReference.cs
src/DocumentChange.cs
Expand Down
52 changes: 52 additions & 0 deletions firestore/src/AggregateQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@


using Firebase.Firestore.Internal;
using System.Threading.Tasks;

namespace Firebase.Firestore {
/// <summary>
/// A query that calculates aggregations over an underlying query.
/// </summary>
public sealed class AggregateQuery
dconeybe marked this conversation as resolved.
Show resolved Hide resolved
{
private readonly AggregateQueryProxy _proxy;
private readonly FirebaseFirestore _firestore;

internal AggregateQuery(AggregateQueryProxy proxy, FirebaseFirestore firestore) {
_proxy = Util.NotNull(proxy);
_firestore = Util.NotNull(firestore);
}

/// <summary>
/// The query of aggregations that will be calculated.
/// </summary>
public Query Query => new Query(_proxy.query(), _firestore);

/// <summary>
/// Asynchronously executes the query.
/// </summary>
/// <param name="source">The source from which to acquire the aggregate results.</param>
/// <returns>The results of the query.</returns>
public Task<AggregateQuerySnapshot> GetSnapshotAsync(AggregateSource source) {
var sourceProxy = Enums.Convert(source);
return Util.MapResult(_proxy.GetAsync(sourceProxy),
taskResult => { return new AggregateQuerySnapshot(taskResult, _firestore); });
}

/// <inheritdoc />
public override bool Equals(object obj) => Equals(obj as Query);
dconeybe marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Compares this aggregate query with another for equality.
/// </summary>
/// <param name="other">The aggregate query to compare this one with.</param>
/// <returns><c>true</c> if this aggregate query is equal to <paramref name="other"/>;
/// <c>false</c> otherwise.</returns>
public bool Equals(AggregateQuery other) => other != null && FirestoreCpp.AggregateQueryEquals(_proxy, other._proxy);

/// <inheritdoc />
public override int GetHashCode() {
return FirestoreCpp.AggregateQueryHashCode(_proxy);
}
}
}
64 changes: 64 additions & 0 deletions firestore/src/AggregateQuerySnapshot.cs
dconeybe marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Firebase.Firestore.Internal;

namespace Firebase.Firestore {
/// <summary>
/// The results of executing an <c>AggregateQuerySnapshot</c>.
/// </summary>
public sealed class AggregateQuerySnapshot {
dconeybe marked this conversation as resolved.
Show resolved Hide resolved
private readonly AggregateQuerySnapshotProxy _proxy;
private readonly FirebaseFirestore _firestore;

internal AggregateQuerySnapshot(AggregateQuerySnapshotProxy proxy, FirebaseFirestore firestore) {
_proxy = Util.NotNull(proxy);
_firestore = Util.NotNull(firestore);
}
/// <summary>
/// Returns the query that was executed to produce this result.
/// </summary>
public AggregateQuery Query {
get {
return new AggregateQuery(_proxy.query(), _firestore);
}
}

/// <summary>
/// Returns the number of documents in the result set of the underlying query.
/// </summary>
public long Count {
get {
return _proxy.count();
}
}

/// <inheritdoc />
public override bool Equals(object obj) => Equals(obj as AggregateQuerySnapshot);

/// <summary>
/// Compares this aggregate snapshot with another for equality.
/// </summary>
/// <param name="other">The aggregate snapshot to compare this one with.</param>
/// <returns><c>true</c> if this aggregate snapshot is equal to <paramref name="other"/>;
/// <c>false</c> otherwise.</returns>
public bool Equals(AggregateQuerySnapshot other) =>
other != null && FirestoreCpp.AggregateQuerySnapshotEquals(_proxy, other._proxy);

/// <inheritdoc />
public override int GetHashCode() {
return FirestoreCpp.AggregateQuerySnapshotHashCode(_proxy);
}
}
}
35 changes: 35 additions & 0 deletions firestore/src/AggregateSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Firebase.Firestore {

/// <summary>
/// The sources from which an <see cref="AggregateQuery.GetSnapshotAsync"/> can retrieve its
/// results.
/// </summary>
public enum AggregateSource {
/// Perform the aggregation on the server and download the result.
/// The result received from the server is presented, unaltered, without
/// considering any local state. That is, documents in the local cache are not
/// taken into consideration, neither are local modifications not yet
/// synchronized with the server. Previously-downloaded results, if any, are
/// not used: every request using this source necessarily involves a round trip
/// to the server.
///
/// The AggregateQuery will fail if the server cannot be reached, such as if
/// the client is offline.
Server,
}

}
21 changes: 21 additions & 0 deletions firestore/src/Query.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,27 @@ public FirebaseFirestore Firestore {
}
}

/// <summary>
/// Returns a query that counts the documents in the result set of this query.
///
/// The returned query, when executed, counts the documents in the result set
/// of this query without actually downloading the documents.
///
/// Using the returned query to count the documents is efficient because only
/// the final count, not the documents' data, is downloaded. The returned query
/// can even count the documents if the result set would be prohibitively large
/// to download entirely (e.g. thousands of documents).
/// </summary>
/// <returns>
/// An aggregate query that counts the documents in the result set of this query.
/// </returns>
public AggregateQuery Count {
get {
return new AggregateQuery(_proxy.Count(), _firestore);
}
}


/// <summary>
/// Creates and returns a new <c>Query</c> with the additional filter that documents must
/// contain the specified field and the value should be equal to the specified value.
Expand Down
9 changes: 9 additions & 0 deletions firestore/src/internal/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ namespace Firebase.Firestore.Internal {
/// documentation purposes -- they are otherwise equivalent to the proxy ones.
static class Enums {

public static AggregateSourceProxy Convert(AggregateSource aggregateSource) {
switch (aggregateSource) {
case AggregateSource.Server:
return AggregateSourceProxy.Server;
default:
throw new System.ArgumentOutOfRangeException("Unexpected enum value: " +
aggregateSource.ToString());
}
}
public static SourceProxy Convert(Source source) {
switch (source) {
case Source.Default:
Expand Down
8 changes: 8 additions & 0 deletions firestore/src/swig/equality_compare.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ namespace firebase {
namespace firestore {
namespace csharp {

bool AggregateQueryEquals(const AggregateQuery* lhs, const AggregateQuery* rhs) {
return EqualityCompareHelper(lhs, rhs);
}

bool AggregateQuerySnapshotEquals(const AggregateQuerySnapshot* lhs, const AggregateQuerySnapshot* rhs) {
return EqualityCompareHelper(lhs, rhs);
}

bool QueryEquals(const Query* lhs, const Query* rhs) {
return EqualityCompareHelper(lhs, rhs);
}
Expand Down
12 changes: 11 additions & 1 deletion firestore/src/swig/equality_compare.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef FIREBASE_FIRESTORE_CLIENT_UNITY_SRC_SWIG_EQUALITY_COMPARE_H_
#define FIREBASE_FIRESTORE_CLIENT_UNITY_SRC_SWIG_EQUALITY_COMPARE_H_

#include "firestore/src/include/firebase/firestore/aggregate_query.h"
#include "firestore/src/include/firebase/firestore/aggregate_query_snapshot.h"
#include "firestore/src/include/firebase/firestore/document_change.h"
#include "firestore/src/include/firebase/firestore/document_snapshot.h"
#include "firestore/src/include/firebase/firestore/query.h"
Expand All @@ -10,7 +12,15 @@ namespace firebase {
namespace firestore {
namespace csharp {

// Compares two `Query` objects for equality using their `==` operator, handling
// Compares two `AggregateQuery` objects for equality using their `==` operator, handling
// one or both of them being `nullptr`.
bool AggregateQueryEquals(const AggregateQuery* lhs, const AggregateQuery* rhs);

// Compares two `AggregateQuerySnapshot` objects for equality using their `==` operator,
// handling one or both of them being `nullptr`.
bool AggregateQuerySnapshotEquals(const AggregateQuerySnapshot* lhs, const AggregateQuerySnapshot* rhs);

// Compares two `Query` objects for equality using their `==` operator, handling
// one or both of them being `nullptr`.
bool QueryEquals(const Query* lhs, const Query* rhs);

Expand Down
19 changes: 19 additions & 0 deletions firestore/src/swig/firestore.i
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ SWIG_MAP_CFUNC_TO_CSDELEGATE(::firebase::firestore::csharp::LoadBundleTaskProgre

// Generate Future instantiations, must be before other wrappers.
%include "app/src/swig/future.i"
%SWIG_FUTURE(Future_AggregateQuerySnapshot, AggregateQuerySnapshotProxy, internal,
firebase::firestore::AggregateQuerySnapshot, FirestoreException)
%SWIG_FUTURE(Future_QuerySnapshot, QuerySnapshotProxy, internal,
firebase::firestore::QuerySnapshot, FirestoreException)
%SWIG_FUTURE(Future_DocumentSnapshot, DocumentSnapshotProxy, internal,
Expand Down Expand Up @@ -250,6 +252,10 @@ SWIG_CREATE_PROXY(firebase::firestore::ListenerRegistration)
SWIG_CREATE_PROXY(firebase::firestore::Source)
%include "firestore/src/include/firebase/firestore/source.h"

// Generate a C# wrapper for Source. Must be before AggregateQuery.
SWIG_CREATE_PROXY(firebase::firestore::AggregateSource)
%include "firestore/src/include/firebase/firestore/aggregate_source.h"

// Generate a C# wrapper for FieldPath. Must be above DocumentSnapshot and SetOptions.
SWIG_CREATE_PROXY(firebase::firestore::FieldPath)
%rename("%s") firebase::firestore::FieldPath::FieldPath(const std::vector<std::string>&);
Expand Down Expand Up @@ -369,6 +375,7 @@ SWIG_CREATE_PROXY(firebase::firestore::Query);
%rename("%s") firebase::firestore::Query::EndBefore(const DocumentSnapshot&) const;
%rename("%s") firebase::firestore::Query::EndAt(const DocumentSnapshot&) const;
%rename("%s") firebase::firestore::Query::Get;
%rename("%s") firebase::firestore::Query::Count;
%rename("%s") firebase::firestore::Query::Direction;
%include "firestore/src/include/firebase/firestore/query.h"

Expand All @@ -387,6 +394,18 @@ SWIG_CREATE_PROXY(firebase::firestore::QuerySnapshot);
%rename("%s") firebase::firestore::QuerySnapshot::size;
%include "firestore/src/include/firebase/firestore/query_snapshot.h"

// Generate a C# wrapper for AggregateQuery. Must be after Query.
SWIG_CREATE_PROXY(firebase::firestore::AggregateQuery);
%rename("%s") firebase::firestore::AggregateQuery::query;
%rename("%s") firebase::firestore::AggregateQuery::Get;
%include "firestore/src/include/firebase/firestore/aggregate_query.h"

// Generate a C# wrapper for AggregateQuerySnapshot. Must be after AggregateQuery.
SWIG_CREATE_PROXY(firebase::firestore::AggregateQuerySnapshot);
%rename("%s") firebase::firestore::AggregateQuerySnapshot::query;
%rename("%s") firebase::firestore::AggregateQuerySnapshot::count;
%include "firestore/src/include/firebase/firestore/aggregate_query_snapshot.h"

// Generate a C# wrapper for Settings.
SWIG_CREATE_PROXY(firebase::firestore::Settings);
%rename("%s") firebase::firestore::Settings::kCacheSizeUnlimited;
Expand Down
20 changes: 20 additions & 0 deletions firestore/src/swig/hash.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ namespace firestore {
// The following functions are declared as friend functions in the corresponding
// classes in the C++ SDK headers.

size_t AggregateQueryHash(const AggregateQuery& query) { return query.Hash(); }

size_t AggregateQuerySnapshotHash(const AggregateQuerySnapshot& snapshot) {
return snapshot.Hash();
}

size_t QueryHash(const Query& query) { return query.Hash(); }

size_t QuerySnapshotHash(const QuerySnapshot& snapshot) {
Expand All @@ -22,6 +28,20 @@ size_t DocumentChangeHash(const DocumentChange& change) {

namespace csharp {

int32_t AggregateQueryHashCode(const AggregateQuery* query) {
if (query == nullptr) {
return 0;
}
return AggregateQueryHash(*query);
}

int32_t AggregateQuerySnapshotHashCode(const AggregateQuerySnapshot* snapshot) {
if (snapshot == nullptr) {
return 0;
}
return AggregateQuerySnapshotHash(*snapshot);
}

int32_t QueryHashCode(const Query* query) {
if (query == nullptr) {
return 0;
Expand Down
8 changes: 8 additions & 0 deletions firestore/src/swig/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include <stdint.h>

#include "firestore/src/include/firebase/firestore/aggregate_query.h"
#include "firestore/src/include/firebase/firestore/aggregate_query_snapshot.h"
#include "firestore/src/include/firebase/firestore/document_change.h"
#include "firestore/src/include/firebase/firestore/document_snapshot.h"
#include "firestore/src/include/firebase/firestore/query.h"
Expand All @@ -12,6 +14,12 @@ namespace firebase {
namespace firestore {
namespace csharp {

// Returns the hash code for the given query.
int32_t AggregateQueryHashCode(const AggregateQuery* query);

// Returns the hash code for the given query snapshot.
int32_t AggregateQuerySnapshotHashCode(const AggregateQuerySnapshot* snapshot);

// Returns the hash code for the given query.
int32_t QueryHashCode(const Query* query);

Expand Down
Loading