Skip to content

Commit 2951a6c

Browse files
committed
expand expr to expression
1 parent fac2f83 commit 2951a6c

File tree

6 files changed

+101
-51
lines changed

6 files changed

+101
-51
lines changed

Firestore/Swift/Source/ExpressionImplementation.swift

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ public extension Expression {
116116
return FunctionExpression("array_get", [self, Helper.sendableToExpr(offset)])
117117
}
118118

119-
func arrayGet(_ offsetExpr: Expression) -> FunctionExpression {
120-
return FunctionExpression("array_get", [self, offsetExpr])
119+
func arrayGet(_ offsetExpression: Expression) -> FunctionExpression {
120+
return FunctionExpression("array_get", [self, offsetExpression])
121121
}
122122

123123
func greaterThan(_ other: Expression) -> BooleanExpression {
@@ -263,8 +263,8 @@ public extension Expression {
263263
return BooleanExpression("string_contains", [self, Helper.sendableToExpr(substring)])
264264
}
265265

266-
func strContains(_ expr: Expression) -> BooleanExpression {
267-
return BooleanExpression("string_contains", [self, expr])
266+
func string_contains(_ expression: Expression) -> BooleanExpression {
267+
return BooleanExpression("string_contains", [self, expression])
268268
}
269269

270270
func startsWith(_ prefix: String) -> BooleanExpression {
@@ -295,7 +295,7 @@ public extension Expression {
295295
return FunctionExpression("trim", [self])
296296
}
297297

298-
func strConcat(_ strings: [Expression]) -> FunctionExpression {
298+
func stringConcat(_ strings: [Expression]) -> FunctionExpression {
299299
return FunctionExpression("string_concat", [self] + strings)
300300
}
301301

@@ -356,8 +356,8 @@ public extension Expression {
356356
return FunctionExpression("map_remove", [self, Helper.sendableToExpr(key)])
357357
}
358358

359-
func mapRemove(_ keyExpr: Expression) -> FunctionExpression {
360-
return FunctionExpression("map_remove", [self, keyExpr])
359+
func mapRemove(_ keyExpression: Expression) -> FunctionExpression {
360+
return FunctionExpression("map_remove", [self, keyExpression])
361361
}
362362

363363
func mapMerge(_ maps: [[String: Sendable]]) -> FunctionExpression {
@@ -559,24 +559,24 @@ public extension Expression {
559559
return FunctionExpression("bit_left_shift", [self, Helper.sendableToExpr(y)])
560560
}
561561

562-
func bitLeftShift(_ numberExpr: Expression) -> FunctionExpression {
563-
return FunctionExpression("bit_left_shift", [self, numberExpr])
562+
func bitLeftShift(_ numberExpression: Expression) -> FunctionExpression {
563+
return FunctionExpression("bit_left_shift", [self, numberExpression])
564564
}
565565

566566
func bitRightShift(_ y: Int) -> FunctionExpression {
567567
return FunctionExpression("bit_right_shift", [self, Helper.sendableToExpr(y)])
568568
}
569569

570-
func bitRightShift(_ numberExpr: Expression) -> FunctionExpression {
571-
return FunctionExpression("bit_right_shift", [self, numberExpr])
570+
func bitRightShift(_ numberExpression: Expression) -> FunctionExpression {
571+
return FunctionExpression("bit_right_shift", [self, numberExpression])
572572
}
573573

574574
func documentId() -> FunctionExpression {
575575
return FunctionExpression("document_id", [self])
576576
}
577577

578-
func ifError(_ catchExpr: Expression) -> FunctionExpression {
579-
return FunctionExpression("if_error", [self, catchExpr])
578+
func ifError(_ catchExpression: Expression) -> FunctionExpression {
579+
return FunctionExpression("if_error", [self, catchExpression])
580580
}
581581

582582
func ifError(_ catchValue: Sendable) -> FunctionExpression {
@@ -586,10 +586,10 @@ public extension Expression {
586586
// MARK: Sorting
587587

588588
func ascending() -> Ordering {
589-
return Ordering(expr: self, direction: .ascending)
589+
return Ordering(expression: self, direction: .ascending)
590590
}
591591

592592
func descending() -> Ordering {
593-
return Ordering(expr: self, direction: .descending)
593+
return Ordering(expression: self, direction: .descending)
594594
}
595595
}

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

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ public protocol Expression: Sendable {
350350
/// - Parameter offsetExpr: An `Expression` (evaluating to an Int) representing the offset of the
351351
/// element to return.
352352
/// - Returns: A new `FunctionExpression` representing the "arrayGet" operation.
353-
func arrayGet(_ offsetExpr: Expression) -> FunctionExpression
353+
func arrayGet(_ offsetExpression: Expression) -> FunctionExpression
354354

355355
/// Creates a `BooleanExpr` that returns `true` if this expression is greater
356356
/// than the given expression.
@@ -699,7 +699,7 @@ public protocol Expression: Sendable {
699699
///
700700
/// ```swift
701701
/// // Check if the "description" field contains "example".
702-
/// Field("description").strContains("example")
702+
/// Field("description").string_contains("example")
703703
/// ```
704704
///
705705
/// - Parameter substring: The literal string substring to search for.
@@ -712,13 +712,13 @@ public protocol Expression: Sendable {
712712
///
713713
/// ```swift
714714
/// // Check if the "message" field contains the value of the "keyword" field.
715-
/// Field("message").strContains(Field("keyword"))
715+
/// Field("message").string_contains(Field("keyword"))
716716
/// ```
717717
///
718718
/// - Parameter expr: An `Expression` (evaluating to a string) representing the substring to
719719
/// search for.
720720
/// - Returns: A new `BooleanExpr` representing the "str_contains" comparison.
721-
func strContains(_ expr: Expression) -> BooleanExpression
721+
func string_contains(_ expression: Expression) -> BooleanExpression
722722

723723
/// Creates an expression that checks if a string (from `self`) starts with a given literal prefix
724724
/// (case-sensitive).
@@ -813,14 +813,14 @@ public protocol Expression: Sendable {
813813
///
814814
/// ```swift
815815
/// // Combine "firstName", "middleName", and "lastName" fields
816-
/// Field("firstName").strConcat(Field("middleName"), Field("lastName"))
816+
/// Field("firstName").stringConcat(Field("middleName"), Field("lastName"))
817817
/// ```
818818
///
819819
/// - Parameter secondString: An `Expression` (evaluating to a string) to concatenate.
820820
/// - Parameter otherStrings: Optional additional `Expression` (evaluating to strings) to
821821
/// concatenate.
822822
/// - Returns: A new `FunctionExpression` representing the concatenated string.
823-
func strConcat(_ strings: [Expression]) -> FunctionExpression
823+
func stringConcat(_ strings: [Expression]) -> FunctionExpression
824824

825825
/// Creates an expression that reverses this string expression.
826826
/// Assumes `self` evaluates to a string.
@@ -989,7 +989,7 @@ public protocol Expression: Sendable {
989989
/// - Parameter keyExpr: An `Expr` (evaluating to a string) representing the key to remove from
990990
/// the map.
991991
/// - Returns: A new `FunctionExpr` representing the "map_remove" operation.
992-
func mapRemove(_ keyExpr: Expression) -> FunctionExpression
992+
func mapRemove(_ keyExpression: Expression) -> FunctionExpression
993993

994994
/// Creates an expression that merges this map with multiple other map literals.
995995
/// Assumes `self` evaluates to a Map. Later maps overwrite keys from earlier maps.
@@ -1584,7 +1584,7 @@ public protocol Expression: Sendable {
15841584
/// ```
15851585
/// - Parameter numberExpr: An `Expr` (evaluating to an Int) for the number of bits to shift by.
15861586
/// - Returns: A new "FunctionExpression" representing the bitwise left shift operation.
1587-
func bitLeftShift(_ numberExpr: Expression) -> FunctionExpression
1587+
func bitLeftShift(_ numberExpression: Expression) -> FunctionExpression
15881588

15891589
/// Creates an expression applying bitwise right shift to this expression by a literal number of
15901590
/// bits.
@@ -1612,7 +1612,7 @@ public protocol Expression: Sendable {
16121612
/// ```
16131613
/// - Parameter numberExpr: An `Expr` (evaluating to an Int) for the number of bits to shift by.
16141614
/// - Returns: A new "FunctionExpression" representing the bitwise right shift operation.
1615-
func bitRightShift(_ numberExpr: Expression) -> FunctionExpression
1615+
func bitRightShift(_ numberExpression: Expression) -> FunctionExpression
16161616

16171617
func documentId() -> FunctionExpression
16181618

Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/BooleanExpression.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public class BooleanExpression: FunctionExpression, @unchecked Sendable {
5252
/// ```
5353
///
5454
/// - Returns: An `AggregateFunction` that performs the conditional count.
55-
public func countIf() -> AggregateFunction {
55+
internal func countIf() -> AggregateFunction {
5656
return AggregateFunction("count_if", [self])
5757
}
5858

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2025 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+
// http://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+
import Foundation
16+
17+
///
18+
/// A `ConditionalExpression` is a `FunctionExpression` that evaluates to one of two expressions
19+
/// based on a boolean condition.
20+
///
21+
/// This is equivalent to a ternary operator (`condition ? then : else`).
22+
///
23+
/// Example of using `ConditionalExpression`:
24+
/// ```swift
25+
/// // Create a new field "status" based on the "rating" field.
26+
/// // If rating > 4.5, status is "top_rated", otherwise "regular".
27+
/// firestore.pipeline()
28+
/// .collection("products")
29+
/// .addFields([
30+
/// ConditionalExpression(
31+
/// Field("rating").greaterThan(4.5),
32+
/// then: Constant("top_rated"),
33+
/// else: Constant("regular")
34+
/// ).as("status")
35+
/// ])
36+
/// ```
37+
public class ConditionalExpression: FunctionExpression, @unchecked Sendable {
38+
/// Creates a new `ConditionalExpression`.
39+
///
40+
/// - Parameters:
41+
/// - expr: The `BooleanExpression` to evaluate.
42+
/// - thenExpression: The `Expression` to evaluate if the boolean expression is `true`.
43+
/// - elseExpression: The `Expression` to evaluate if the boolean expression is `false`.
44+
public init(_ expr: BooleanExpression,
45+
then thenExpression: Expression,
46+
else elseExpression: Expression) {
47+
super.init("conditional", [expr, thenExpression, elseExpression])
48+
}
49+
}

Firestore/Swift/Source/SwiftAPI/Pipeline/Ordering.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ public struct Ordering: @unchecked Sendable {
1919
let direction: Direction
2020
let bridge: OrderingBridge
2121

22-
init(expr: Expression, direction: Direction) {
23-
self.expr = expr
22+
init(expression: Expression, direction: Direction) {
23+
self.expr = expression
2424
self.direction = direction
25-
bridge = OrderingBridge(expr: expr.toBridge(), direction: direction.rawValue)
25+
bridge = OrderingBridge(expr: expression.toBridge(), direction: direction.rawValue)
2626
}
2727
}
2828

Firestore/Swift/Tests/Integration/PipelineTests.swift

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -823,27 +823,28 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
823823
XCTFail("No result for min/max/count/countAll aggregation")
824824
}
825825
}
826-
827-
func testReturnsCountIfAccumulation() async throws {
828-
let collRef = collectionRef(withDocuments: bookDocs)
829-
let db = collRef.firestore
830-
831-
let expectedCount = 3
832-
let expectedResults: [String: Sendable] = ["count": expectedCount]
833-
let condition = Field("rating").greaterThan(4.3)
834-
835-
let pipeline = db.pipeline()
836-
.collection(collRef.path)
837-
.aggregate([condition.countIf().as("count")])
838-
let snapshot = try await pipeline.execute()
839-
840-
XCTAssertEqual(snapshot.results.count, 1, "countIf aggregate should return a single document")
841-
if let result = snapshot.results.first {
842-
TestHelper.compare(pipelineResult: result, expected: expectedResults)
843-
} else {
844-
XCTFail("No result for countIf aggregation")
845-
}
846-
}
826+
827+
// Hide this test due to `.countIf()` design is incomplete.
828+
// func testReturnsCountIfAccumulation() async throws {
829+
// let collRef = collectionRef(withDocuments: bookDocs)
830+
// let db = collRef.firestore
831+
//
832+
// let expectedCount = 3
833+
// let expectedResults: [String: Sendable] = ["count": expectedCount]
834+
// let condition = Field("rating").greaterThan(4.3)
835+
//
836+
// let pipeline = db.pipeline()
837+
// .collection(collRef.path)
838+
// .aggregate([condition.countIf().as("count")])
839+
// let snapshot = try await pipeline.execute()
840+
//
841+
// XCTAssertEqual(snapshot.results.count, 1, "countIf aggregate should return a single document")
842+
// if let result = snapshot.results.first {
843+
// TestHelper.compare(pipelineResult: result, expected: expectedResults)
844+
// } else {
845+
// XCTFail("No result for countIf aggregation")
846+
// }
847+
// }
847848

848849
func testDistinctStage() async throws {
849850
let collRef = collectionRef(withDocuments: bookDocs)
@@ -1130,7 +1131,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
11301131
name: "add_fields",
11311132
params: [
11321133
[
1133-
"display": Field("title").strConcat([
1134+
"display": Field("title").stringConcat([
11341135
Constant(" - "),
11351136
Field("author"),
11361137
]),
@@ -1767,7 +1768,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
17671768
let pipeline = db.pipeline()
17681769
.collection(collRef.path)
17691770
.sort([Field("author").ascending()])
1770-
.select([Field("author").strConcat([Constant(" - "), Field("title")]).as("bookInfo")])
1771+
.select([Field("author").stringConcat([Constant(" - "), Field("title")]).as("bookInfo")])
17711772
.limit(1)
17721773

17731774
let snapshot = try await pipeline.execute()

0 commit comments

Comments
 (0)