Skip to content

Commit 11bf771

Browse files
committed
add countDistinct()
1 parent d5d5c9d commit 11bf771

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

Firestore/Swift/Source/ExpressionImplementation.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,10 @@ public extension Expression {
383383

384384
// --- Added Aggregate Operations (on Expr) ---
385385

386+
func countDistinct() -> AggregateFunction {
387+
return AggregateFunction("count_distinct", [self])
388+
}
389+
386390
func count() -> AggregateFunction {
387391
return AggregateFunction("count", [self])
388392
}

Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Expression.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,16 @@ public protocol Expression: Sendable {
10541054

10551055
// MARK: Aggregations
10561056

1057+
/// Creates an aggregation that counts the number of distinct values of this expression.
1058+
///
1059+
/// ```swift
1060+
/// // Count the number of distinct categories.
1061+
/// Field("category").countDistinct().as("distinctCategories")
1062+
/// ```
1063+
///
1064+
/// - Returns: A new `AggregateFunction` representing the "count_distinct" aggregation.
1065+
func countDistinct() -> AggregateFunction
1066+
10571067
/// Creates an aggregation that counts the number of stage inputs where this expression evaluates
10581068
/// to a valid, non-null value.
10591069
///

Firestore/Swift/Tests/Integration/PipelineTests.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,31 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
824824
}
825825
}
826826

827+
func testReturnsCountDistinctAccumulation() async throws {
828+
let collRef = collectionRef(withDocuments: bookDocs)
829+
let db = collRef.firestore
830+
831+
let pipeline = db.pipeline()
832+
.collection(collRef.path)
833+
.aggregate([
834+
Field("genre").countDistinct().as("distinctGenres"),
835+
])
836+
837+
let snapshot = try await pipeline.execute()
838+
839+
XCTAssertEqual(snapshot.results.count, 1, "Aggregate should return a single document")
840+
841+
let expectedValues: [String: Sendable] = [
842+
"distinctGenres": 8,
843+
]
844+
845+
if let result = snapshot.results.first {
846+
TestHelper.compare(pipelineResult: result, expected: expectedValues)
847+
} else {
848+
XCTFail("No result for countDistinct aggregation")
849+
}
850+
}
851+
827852
// Hide this test due to `.countIf()` design is incomplete.
828853
// func testReturnsCountIfAccumulation() async throws {
829854
// let collRef = collectionRef(withDocuments: bookDocs)

0 commit comments

Comments
 (0)