Selaa lähdekoodia

Add documentation for ppl (#15401)

Co-authored-by: wu-hui <wu.hui.github@gmail.com>
cherylEnkidu 5 kuukautta sitten
vanhempi
sitoutus
680503d453
25 muutettua tiedostoa jossa 963 lisäystä ja 627 poistoa
  1. 270 165
      Firestore/Swift/Source/ExpressionImplementation.swift
  2. 2 2
      Firestore/Swift/Source/Helper/PipelineHelper.swift
  3. 0 0
      Firestore/Swift/Source/Stages.swift
  4. 30 0
      Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift
  5. 15 1
      Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/AggregateFunction.swift
  6. 4 2
      Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/AliasedAggregate.swift
  7. 1 1
      Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/CountAll.swift
  8. 4 0
      Firestore/Swift/Source/SwiftAPI/Pipeline/DistanceMeasure.swift
  9. 1 0
      Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/AliasedExpression.swift
  10. 204 161
      Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Expression.swift
  11. 5 1
      Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Field.swift
  12. 1 1
      Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ArrayExpression.swift
  13. 12 9
      Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/BooleanExpression.swift
  14. 2 2
      Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ConditionalExpression.swift
  15. 1 1
      Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/CurrentTimestamp.swift
  16. 1 1
      Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ErrorExpression.swift
  17. 16 4
      Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/FunctionExpression.swift
  18. 1 1
      Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/MapExpression.swift
  19. 3 3
      Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/RandomExpression.swift
  20. 7 0
      Firestore/Swift/Source/SwiftAPI/Pipeline/Ordering.swift
  21. 13 17
      Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift
  22. 33 0
      Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift
  23. 8 0
      Firestore/Swift/Source/SwiftAPI/Pipeline/Selectable.swift
  24. 3 3
      Firestore/Swift/Tests/Integration/PipelineApiTests.swift
  25. 326 252
      Firestore/Swift/Tests/Integration/PipelineTests.swift

+ 270 - 165
Firestore/Swift/Source/ExpressionImplementation.swift

@@ -30,7 +30,10 @@ extension Expression {
   /// - Parameter otherBits: The integer literal operand.
   /// - Returns: A new "FunctionExpression" representing the bitwise AND operation.
   func bitAnd(_ otherBits: Int) -> FunctionExpression {
-    return FunctionExpression("bit_and", [self, Helper.sendableToExpr(otherBits)])
+    return FunctionExpression(
+      functionName: "bit_and",
+      args: [self, Helper.sendableToExpr(otherBits)]
+    )
   }
 
   /// Creates an expression applying bitwise AND between this expression and a UInt8 literal (often
@@ -44,7 +47,10 @@ extension Expression {
   /// - Parameter otherBits: The UInt8 literal operand.
   /// - Returns: A new "FunctionExpression" representing the bitwise AND operation.
   func bitAnd(_ otherBits: UInt8) -> FunctionExpression {
-    return FunctionExpression("bit_and", [self, Helper.sendableToExpr(otherBits)])
+    return FunctionExpression(
+      functionName: "bit_and",
+      args: [self, Helper.sendableToExpr(otherBits)]
+    )
   }
 
   /// Creates an expression applying bitwise AND between this expression and another expression.
@@ -58,7 +64,7 @@ extension Expression {
   /// - Parameter bitsExpression: The other `Expr` operand.
   /// - Returns: A new "FunctionExpression" representing the bitwise AND operation.
   func bitAnd(_ bitsExpression: Expression) -> FunctionExpression {
-    return FunctionExpression("bit_and", [self, bitsExpression])
+    return FunctionExpression(functionName: "bit_and", args: [self, bitsExpression])
   }
 
   /// Creates an expression applying bitwise OR between this expression and an integer literal.
@@ -74,7 +80,10 @@ extension Expression {
   /// - Parameter otherBits: The integer literal operand.
   /// - Returns: A new "FunctionExpression" representing the bitwise OR operation.
   func bitOr(_ otherBits: Int) -> FunctionExpression {
-    return FunctionExpression("bit_or", [self, Helper.sendableToExpr(otherBits)])
+    return FunctionExpression(
+      functionName: "bit_or",
+      args: [self, Helper.sendableToExpr(otherBits)]
+    )
   }
 
   /// Creates an expression applying bitwise OR between this expression and a UInt8 literal.
@@ -87,7 +96,10 @@ extension Expression {
   /// - Parameter otherBits: The UInt8 literal operand.
   /// - Returns: A new "FunctionExpression" representing the bitwise OR operation.
   func bitOr(_ otherBits: UInt8) -> FunctionExpression {
-    return FunctionExpression("bit_or", [self, Helper.sendableToExpr(otherBits)])
+    return FunctionExpression(
+      functionName: "bit_or",
+      args: [self, Helper.sendableToExpr(otherBits)]
+    )
   }
 
   /// Creates an expression applying bitwise OR between this expression and another expression.
@@ -101,7 +113,7 @@ extension Expression {
   /// - Parameter bitsExpression: The other `Expr` operand.
   /// - Returns: A new "FunctionExpression" representing the bitwise OR operation.
   func bitOr(_ bitsExpression: Expression) -> FunctionExpression {
-    return FunctionExpression("bit_or", [self, bitsExpression])
+    return FunctionExpression(functionName: "bit_or", args: [self, bitsExpression])
   }
 
   /// Creates an expression applying bitwise XOR between this expression and an integer literal.
@@ -117,7 +129,10 @@ extension Expression {
   /// - Parameter otherBits: The integer literal operand.
   /// - Returns: A new "FunctionExpression" representing the bitwise XOR operation.
   func bitXor(_ otherBits: Int) -> FunctionExpression {
-    return FunctionExpression("bit_xor", [self, Helper.sendableToExpr(otherBits)])
+    return FunctionExpression(
+      functionName: "bit_xor",
+      args: [self, Helper.sendableToExpr(otherBits)]
+    )
   }
 
   /// Creates an expression applying bitwise XOR between this expression and a UInt8 literal.
@@ -130,7 +145,10 @@ extension Expression {
   /// - Parameter otherBits: The UInt8 literal operand.
   /// - Returns: A new "FunctionExpression" representing the bitwise XOR operation.
   func bitXor(_ otherBits: UInt8) -> FunctionExpression {
-    return FunctionExpression("bit_xor", [self, Helper.sendableToExpr(otherBits)])
+    return FunctionExpression(
+      functionName: "bit_xor",
+      args: [self, Helper.sendableToExpr(otherBits)]
+    )
   }
 
   /// Creates an expression applying bitwise XOR between this expression and another expression.
@@ -144,7 +162,7 @@ extension Expression {
   /// - Parameter bitsExpression: The other `Expr` operand.
   /// - Returns: A new "FunctionExpression" representing the bitwise XOR operation.
   func bitXor(_ bitsExpression: Expression) -> FunctionExpression {
-    return FunctionExpression("bit_xor", [self, bitsExpression])
+    return FunctionExpression(functionName: "bit_xor", args: [self, bitsExpression])
   }
 
   /// Creates an expression applying bitwise NOT to this expression.
@@ -159,7 +177,7 @@ extension Expression {
   ///
   /// - Returns: A new "FunctionExpression" representing the bitwise NOT operation.
   func bitNot() -> FunctionExpression {
-    return FunctionExpression("bit_not", [self])
+    return FunctionExpression(functionName: "bit_not", args: [self])
   }
 
   /// Creates an expression applying bitwise left shift to this expression by a literal number of
@@ -176,7 +194,10 @@ extension Expression {
   /// - Parameter y: The number of bits (Int literal) to shift by.
   /// - Returns: A new "FunctionExpression" representing the bitwise left shift operation.
   func bitLeftShift(_ y: Int) -> FunctionExpression {
-    return FunctionExpression("bit_left_shift", [self, Helper.sendableToExpr(y)])
+    return FunctionExpression(
+      functionName: "bit_left_shift",
+      args: [self, Helper.sendableToExpr(y)]
+    )
   }
 
   /// Creates an expression applying bitwise left shift to this expression by a number of bits
@@ -191,7 +212,7 @@ extension Expression {
   /// - Parameter numberExpr: An `Expr` (evaluating to an Int) for the number of bits to shift by.
   /// - Returns: A new "FunctionExpression" representing the bitwise left shift operation.
   func bitLeftShift(_ numberExpression: Expression) -> FunctionExpression {
-    return FunctionExpression("bit_left_shift", [self, numberExpression])
+    return FunctionExpression(functionName: "bit_left_shift", args: [self, numberExpression])
   }
 
   /// Creates an expression applying bitwise right shift to this expression by a literal number of
@@ -208,7 +229,10 @@ extension Expression {
   /// - Parameter y: The number of bits (Int literal) to shift by.
   /// - Returns: A new "FunctionExpression" representing the bitwise right shift operation.
   func bitRightShift(_ y: Int) -> FunctionExpression {
-    return FunctionExpression("bit_right_shift", [self, Helper.sendableToExpr(y)])
+    return FunctionExpression(
+      functionName: "bit_right_shift",
+      args: [self, Helper.sendableToExpr(y)]
+    )
   }
 
   /// Creates an expression applying bitwise right shift to this expression by a number of bits
@@ -223,7 +247,7 @@ extension Expression {
   /// - Parameter numberExpr: An `Expr` (evaluating to an Int) for the number of bits to shift by.
   /// - Returns: A new "FunctionExpression" representing the bitwise right shift operation.
   func bitRightShift(_ numberExpression: Expression) -> FunctionExpression {
-    return FunctionExpression("bit_right_shift", [self, numberExpression])
+    return FunctionExpression(functionName: "bit_right_shift", args: [self, numberExpression])
   }
 
   /// Calculates the Manhattan (L1) distance between this vector expression and another vector
@@ -240,7 +264,7 @@ extension Expression {
   /// - Parameter expression: The other vector as an `Expr` to compare against.
   /// - Returns: A new `FunctionExpression` representing the Manhattan distance.
   func manhattanDistance(_ expression: Expression) -> FunctionExpression {
-    return FunctionExpression("manhattan_distance", [self, expression])
+    return FunctionExpression(functionName: "manhattan_distance", args: [self, expression])
   }
 
   /// Calculates the Manhattan (L1) distance between this vector expression and another vector
@@ -254,7 +278,10 @@ extension Expression {
   /// - Parameter vector: The other vector as a `VectorValue` to compare against.
   /// - Returns: A new `FunctionExpression` representing the Manhattan distance.
   func manhattanDistance(_ vector: VectorValue) -> FunctionExpression {
-    return FunctionExpression("manhattan_distance", [self, Helper.sendableToExpr(vector)])
+    return FunctionExpression(
+      functionName: "manhattan_distance",
+      args: [self, Helper.sendableToExpr(vector)]
+    )
   }
 
   /// Calculates the Manhattan (L1) distance between this vector expression and another vector
@@ -269,7 +296,10 @@ extension Expression {
   /// - Parameter vector: The other vector as `[Double]` to compare against.
   /// - Returns: A new `FunctionExpression` representing the Manhattan distance.
   func manhattanDistance(_ vector: [Double]) -> FunctionExpression {
-    return FunctionExpression("manhattan_distance", [self, Helper.sendableToExpr(vector)])
+    return FunctionExpression(
+      functionName: "manhattan_distance",
+      args: [self, Helper.sendableToExpr(vector)]
+    )
   }
 
   /// Creates an expression that replaces the first occurrence of a literal substring within this
@@ -286,8 +316,8 @@ extension Expression {
   /// - Returns: A new `FunctionExpr` representing the string with the first occurrence replaced.
   func replaceFirst(_ find: String, with replace: String) -> FunctionExpression {
     return FunctionExpression(
-      "replace_first",
-      [self, Helper.sendableToExpr(find), Helper.sendableToExpr(replace)]
+      functionName: "replace_first",
+      args: [self, Helper.sendableToExpr(find), Helper.sendableToExpr(replace)]
     )
   }
 
@@ -305,7 +335,7 @@ extension Expression {
   /// occurrence with.
   /// - Returns: A new `FunctionExpr` representing the string with the first occurrence replaced.
   func replaceFirst(_ find: Expression, with replace: Expression) -> FunctionExpression {
-    return FunctionExpression("replace_first", [self, find, replace])
+    return FunctionExpression(functionName: "replace_first", args: [self, find, replace])
   }
 
   /// Creates an expression that replaces all occurrences of a literal substring within this string
@@ -322,8 +352,8 @@ extension Expression {
   /// - Returns: A new `FunctionExpr` representing the string with all occurrences replaced.
   func stringReplace(_ find: String, with replace: String) -> FunctionExpression {
     return FunctionExpression(
-      "string_replace",
-      [self, Helper.sendableToExpr(find), Helper.sendableToExpr(replace)]
+      functionName: "string_replace",
+      args: [self, Helper.sendableToExpr(find), Helper.sendableToExpr(replace)]
     )
   }
 
@@ -341,18 +371,7 @@ extension Expression {
   /// occurrences with.
   /// - Returns: A new `FunctionExpression` representing the string with all occurrences replaced.
   func stringReplace(_ find: Expression, with replace: Expression) -> FunctionExpression {
-    return FunctionExpression("string_replace", [self, find, replace])
-  }
-
-  // MARK: Equivalence Operations
-
-  /// Creates a `BooleanExpr` that returns `true` if this expression is equivalent
-  /// to the given value.
-  ///
-  /// - Parameter other: The value to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
-  func equivalent(_ other: Sendable) -> BooleanExpression {
-    return BooleanExpression("equivalent", [self, Helper.sendableToExpr(other)])
+    return FunctionExpression(functionName: "string_replace", args: [self, find, replace])
   }
 }
 
@@ -364,215 +383,221 @@ public extension Expression {
   // MARK: Arithmetic Operators
 
   func abs() -> FunctionExpression {
-    return FunctionExpression("abs", [self])
+    return FunctionExpression(functionName: "abs", args: [self])
   }
 
   func ceil() -> FunctionExpression {
-    return FunctionExpression("ceil", [self])
+    return FunctionExpression(functionName: "ceil", args: [self])
   }
 
   func floor() -> FunctionExpression {
-    return FunctionExpression("floor", [self])
+    return FunctionExpression(functionName: "floor", args: [self])
   }
 
   func ln() -> FunctionExpression {
-    return FunctionExpression("ln", [self])
+    return FunctionExpression(functionName: "ln", args: [self])
   }
 
   func pow(_ exponent: Sendable) -> FunctionExpression {
-    return FunctionExpression("pow", [self, Helper.sendableToExpr(exponent)])
+    return FunctionExpression(functionName: "pow", args: [self, Helper.sendableToExpr(exponent)])
   }
 
   func pow(_ exponent: Expression) -> FunctionExpression {
-    return FunctionExpression("pow", [self, exponent])
+    return FunctionExpression(functionName: "pow", args: [self, exponent])
   }
 
   func round() -> FunctionExpression {
-    return FunctionExpression("round", [self])
+    return FunctionExpression(functionName: "round", args: [self])
   }
 
   func sqrt() -> FunctionExpression {
-    return FunctionExpression("sqrt", [self])
+    return FunctionExpression(functionName: "sqrt", args: [self])
   }
 
   func exp() -> FunctionExpression {
-    return FunctionExpression("exp", [self])
+    return FunctionExpression(functionName: "exp", args: [self])
   }
 
   func add(_ value: Expression) -> FunctionExpression {
-    return FunctionExpression("add", [self, value])
+    return FunctionExpression(functionName: "add", args: [self, value])
   }
 
   func add(_ value: Sendable) -> FunctionExpression {
-    return FunctionExpression("add", [self, Helper.sendableToExpr(value)])
+    return FunctionExpression(functionName: "add", args: [self, Helper.sendableToExpr(value)])
   }
 
   func subtract(_ other: Expression) -> FunctionExpression {
-    return FunctionExpression("subtract", [self, other])
+    return FunctionExpression(functionName: "subtract", args: [self, other])
   }
 
   func subtract(_ other: Sendable) -> FunctionExpression {
-    return FunctionExpression("subtract", [self, Helper.sendableToExpr(other)])
+    return FunctionExpression(functionName: "subtract", args: [self, Helper.sendableToExpr(other)])
   }
 
   func multiply(_ value: Expression) -> FunctionExpression {
-    return FunctionExpression("multiply", [self, value])
+    return FunctionExpression(functionName: "multiply", args: [self, value])
   }
 
   func multiply(_ value: Sendable) -> FunctionExpression {
-    return FunctionExpression("multiply", [self, Helper.sendableToExpr(value)])
+    return FunctionExpression(functionName: "multiply", args: [self, Helper.sendableToExpr(value)])
   }
 
   func divide(_ other: Expression) -> FunctionExpression {
-    return FunctionExpression("divide", [self, other])
+    return FunctionExpression(functionName: "divide", args: [self, other])
   }
 
   func divide(_ other: Sendable) -> FunctionExpression {
-    return FunctionExpression("divide", [self, Helper.sendableToExpr(other)])
+    return FunctionExpression(functionName: "divide", args: [self, Helper.sendableToExpr(other)])
   }
 
   func mod(_ other: Expression) -> FunctionExpression {
-    return FunctionExpression("mod", [self, other])
+    return FunctionExpression(functionName: "mod", args: [self, other])
   }
 
   func mod(_ other: Sendable) -> FunctionExpression {
-    return FunctionExpression("mod", [self, Helper.sendableToExpr(other)])
+    return FunctionExpression(functionName: "mod", args: [self, Helper.sendableToExpr(other)])
   }
 
   // MARK: Array Operations
 
   func arrayReverse() -> FunctionExpression {
-    return FunctionExpression("array_reverse", [self])
+    return FunctionExpression(functionName: "array_reverse", args: [self])
   }
 
   func arrayConcat(_ arrays: [Expression]) -> FunctionExpression {
-    return FunctionExpression("array_concat", [self] + arrays)
+    return FunctionExpression(functionName: "array_concat", args: [self] + arrays)
   }
 
   func arrayConcat(_ arrays: [[Sendable]]) -> FunctionExpression {
     let exprs = [self] + arrays.map { Helper.sendableToExpr($0) }
-    return FunctionExpression("array_concat", exprs)
+    return FunctionExpression(functionName: "array_concat", args: exprs)
   }
 
   func arrayContains(_ element: Expression) -> BooleanExpression {
-    return BooleanExpression("array_contains", [self, element])
+    return BooleanExpression(functionName: "array_contains", args: [self, element])
   }
 
   func arrayContains(_ element: Sendable) -> BooleanExpression {
-    return BooleanExpression("array_contains", [self, Helper.sendableToExpr(element)])
+    return BooleanExpression(
+      functionName: "array_contains",
+      args: [self, Helper.sendableToExpr(element)]
+    )
   }
 
   func arrayContainsAll(_ values: [Expression]) -> BooleanExpression {
-    return BooleanExpression("array_contains_all", [self, Helper.array(values)])
+    return BooleanExpression(functionName: "array_contains_all", args: [self, Helper.array(values)])
   }
 
   func arrayContainsAll(_ values: [Sendable]) -> BooleanExpression {
-    return BooleanExpression("array_contains_all", [self, Helper.array(values)])
+    return BooleanExpression(functionName: "array_contains_all", args: [self, Helper.array(values)])
   }
 
   func arrayContainsAll(_ arrayExpression: Expression) -> BooleanExpression {
-    return BooleanExpression("array_contains_all", [self, arrayExpression])
+    return BooleanExpression(functionName: "array_contains_all", args: [self, arrayExpression])
   }
 
   func arrayContainsAny(_ values: [Expression]) -> BooleanExpression {
-    return BooleanExpression("array_contains_any", [self, Helper.array(values)])
+    return BooleanExpression(functionName: "array_contains_any", args: [self, Helper.array(values)])
   }
 
   func arrayContainsAny(_ values: [Sendable]) -> BooleanExpression {
-    return BooleanExpression("array_contains_any", [self, Helper.array(values)])
+    return BooleanExpression(functionName: "array_contains_any", args: [self, Helper.array(values)])
   }
 
   func arrayContainsAny(_ arrayExpression: Expression) -> BooleanExpression {
-    return BooleanExpression("array_contains_any", [self, arrayExpression])
+    return BooleanExpression(functionName: "array_contains_any", args: [self, arrayExpression])
   }
 
   func arrayLength() -> FunctionExpression {
-    return FunctionExpression("array_length", [self])
+    return FunctionExpression(functionName: "array_length", args: [self])
   }
 
   func arrayGet(_ offset: Int) -> FunctionExpression {
-    return FunctionExpression("array_get", [self, Helper.sendableToExpr(offset)])
+    return FunctionExpression(
+      functionName: "array_get",
+      args: [self, Helper.sendableToExpr(offset)]
+    )
   }
 
   func arrayGet(_ offsetExpression: Expression) -> FunctionExpression {
-    return FunctionExpression("array_get", [self, offsetExpression])
+    return FunctionExpression(functionName: "array_get", args: [self, offsetExpression])
   }
 
   func greaterThan(_ other: Expression) -> BooleanExpression {
-    return BooleanExpression("greater_than", [self, other])
+    return BooleanExpression(functionName: "greater_than", args: [self, other])
   }
 
   func greaterThan(_ other: Sendable) -> BooleanExpression {
     let exprOther = Helper.sendableToExpr(other)
-    return BooleanExpression("greater_than", [self, exprOther])
+    return BooleanExpression(functionName: "greater_than", args: [self, exprOther])
   }
 
   func greaterThanOrEqual(_ other: Expression) -> BooleanExpression {
-    return BooleanExpression("greater_than_or_equal", [self, other])
+    return BooleanExpression(functionName: "greater_than_or_equal", args: [self, other])
   }
 
   func greaterThanOrEqual(_ other: Sendable) -> BooleanExpression {
     let exprOther = Helper.sendableToExpr(other)
-    return BooleanExpression("greater_than_or_equal", [self, exprOther])
+    return BooleanExpression(functionName: "greater_than_or_equal", args: [self, exprOther])
   }
 
   func lessThan(_ other: Expression) -> BooleanExpression {
-    return BooleanExpression("less_than", [self, other])
+    return BooleanExpression(functionName: "less_than", args: [self, other])
   }
 
   func lessThan(_ other: Sendable) -> BooleanExpression {
     let exprOther = Helper.sendableToExpr(other)
-    return BooleanExpression("less_than", [self, exprOther])
+    return BooleanExpression(functionName: "less_than", args: [self, exprOther])
   }
 
   func lessThanOrEqual(_ other: Expression) -> BooleanExpression {
-    return BooleanExpression("less_than_or_equal", [self, other])
+    return BooleanExpression(functionName: "less_than_or_equal", args: [self, other])
   }
 
   func lessThanOrEqual(_ other: Sendable) -> BooleanExpression {
     let exprOther = Helper.sendableToExpr(other)
-    return BooleanExpression("less_than_or_equal", [self, exprOther])
+    return BooleanExpression(functionName: "less_than_or_equal", args: [self, exprOther])
   }
 
   func equal(_ other: Expression) -> BooleanExpression {
-    return BooleanExpression("equal", [self, other])
+    return BooleanExpression(functionName: "equal", args: [self, other])
   }
 
   func equal(_ other: Sendable) -> BooleanExpression {
     let exprOther = Helper.sendableToExpr(other)
-    return BooleanExpression("equal", [self, exprOther])
+    return BooleanExpression(functionName: "equal", args: [self, exprOther])
   }
 
   func notEqual(_ other: Expression) -> BooleanExpression {
-    return BooleanExpression("not_equal", [self, other])
+    return BooleanExpression(functionName: "not_equal", args: [self, other])
   }
 
   func notEqual(_ other: Sendable) -> BooleanExpression {
-    return BooleanExpression("not_equal", [self, Helper.sendableToExpr(other)])
+    return BooleanExpression(functionName: "not_equal", args: [self, Helper.sendableToExpr(other)])
   }
 
   func equalAny(_ others: [Expression]) -> BooleanExpression {
-    return BooleanExpression("equal_any", [self, Helper.array(others)])
+    return BooleanExpression(functionName: "equal_any", args: [self, Helper.array(others)])
   }
 
   func equalAny(_ others: [Sendable]) -> BooleanExpression {
-    return BooleanExpression("equal_any", [self, Helper.array(others)])
+    return BooleanExpression(functionName: "equal_any", args: [self, Helper.array(others)])
   }
 
   func equalAny(_ arrayExpression: Expression) -> BooleanExpression {
-    return BooleanExpression("equal_any", [self, arrayExpression])
+    return BooleanExpression(functionName: "equal_any", args: [self, arrayExpression])
   }
 
   func notEqualAny(_ others: [Expression]) -> BooleanExpression {
-    return BooleanExpression("not_equal_any", [self, Helper.array(others)])
+    return BooleanExpression(functionName: "not_equal_any", args: [self, Helper.array(others)])
   }
 
   func notEqualAny(_ others: [Sendable]) -> BooleanExpression {
-    return BooleanExpression("not_equal_any", [self, Helper.array(others)])
+    return BooleanExpression(functionName: "not_equal_any", args: [self, Helper.array(others)])
   }
 
   func notEqualAny(_ arrayExpression: Expression) -> BooleanExpression {
-    return BooleanExpression("not_equal_any", [self, arrayExpression])
+    return BooleanExpression(functionName: "not_equal_any", args: [self, arrayExpression])
   }
 
   // MARK: Checks
@@ -580,322 +605,402 @@ public extension Expression {
   // --- Added Type Check Operations ---
 
   func isNan() -> BooleanExpression {
-    return BooleanExpression("is_nan", [self])
+    return BooleanExpression(functionName: "is_nan", args: [self])
   }
 
   func isNil() -> BooleanExpression {
-    return BooleanExpression("is_null", [self])
+    return BooleanExpression(functionName: "is_null", args: [self])
   }
 
   func exists() -> BooleanExpression {
-    return BooleanExpression("exists", [self])
+    return BooleanExpression(functionName: "exists", args: [self])
   }
 
   func isError() -> BooleanExpression {
-    return BooleanExpression("is_error", [self])
+    return BooleanExpression(functionName: "is_error", args: [self])
   }
 
   func isAbsent() -> BooleanExpression {
-    return BooleanExpression("is_absent", [self])
+    return BooleanExpression(functionName: "is_absent", args: [self])
   }
 
   func isNotNil() -> BooleanExpression {
-    return BooleanExpression("is_not_null", [self])
+    return BooleanExpression(functionName: "is_not_null", args: [self])
   }
 
   func isNotNan() -> BooleanExpression {
-    return BooleanExpression("is_not_nan", [self])
+    return BooleanExpression(functionName: "is_not_nan", args: [self])
   }
 
   // --- Added String Operations ---
 
   func join(delimiter: String) -> FunctionExpression {
-    return FunctionExpression("join", [self, Constant(delimiter)])
+    return FunctionExpression(functionName: "join", args: [self, Constant(delimiter)])
   }
 
   func length() -> FunctionExpression {
-    return FunctionExpression("length", [self])
+    return FunctionExpression(functionName: "length", args: [self])
   }
 
   func charLength() -> FunctionExpression {
-    return FunctionExpression("char_length", [self])
+    return FunctionExpression(functionName: "char_length", args: [self])
   }
 
   func like(_ pattern: String) -> BooleanExpression {
-    return BooleanExpression("like", [self, Helper.sendableToExpr(pattern)])
+    return BooleanExpression(functionName: "like", args: [self, Helper.sendableToExpr(pattern)])
   }
 
   func like(_ pattern: Expression) -> BooleanExpression {
-    return BooleanExpression("like", [self, pattern])
+    return BooleanExpression(functionName: "like", args: [self, pattern])
   }
 
   func regexContains(_ pattern: String) -> BooleanExpression {
-    return BooleanExpression("regex_contains", [self, Helper.sendableToExpr(pattern)])
+    return BooleanExpression(
+      functionName: "regex_contains",
+      args: [self, Helper.sendableToExpr(pattern)]
+    )
   }
 
   func regexContains(_ pattern: Expression) -> BooleanExpression {
-    return BooleanExpression("regex_contains", [self, pattern])
+    return BooleanExpression(functionName: "regex_contains", args: [self, pattern])
   }
 
   func regexMatch(_ pattern: String) -> BooleanExpression {
-    return BooleanExpression("regex_match", [self, Helper.sendableToExpr(pattern)])
+    return BooleanExpression(
+      functionName: "regex_match",
+      args: [self, Helper.sendableToExpr(pattern)]
+    )
   }
 
   func regexMatch(_ pattern: Expression) -> BooleanExpression {
-    return BooleanExpression("regex_match", [self, pattern])
+    return BooleanExpression(functionName: "regex_match", args: [self, pattern])
   }
 
   func stringContains(_ substring: String) -> BooleanExpression {
-    return BooleanExpression("string_contains", [self, Helper.sendableToExpr(substring)])
+    return BooleanExpression(
+      functionName: "string_contains",
+      args: [self, Helper.sendableToExpr(substring)]
+    )
   }
 
   func stringContains(_ expression: Expression) -> BooleanExpression {
-    return BooleanExpression("string_contains", [self, expression])
+    return BooleanExpression(functionName: "string_contains", args: [self, expression])
   }
 
   func startsWith(_ prefix: String) -> BooleanExpression {
-    return BooleanExpression("starts_with", [self, Helper.sendableToExpr(prefix)])
+    return BooleanExpression(
+      functionName: "starts_with",
+      args: [self, Helper.sendableToExpr(prefix)]
+    )
   }
 
   func startsWith(_ prefix: Expression) -> BooleanExpression {
-    return BooleanExpression("starts_with", [self, prefix])
+    return BooleanExpression(functionName: "starts_with", args: [self, prefix])
   }
 
   func endsWith(_ suffix: String) -> BooleanExpression {
-    return BooleanExpression("ends_with", [self, Helper.sendableToExpr(suffix)])
+    return BooleanExpression(functionName: "ends_with", args: [self, Helper.sendableToExpr(suffix)])
   }
 
   func endsWith(_ suffix: Expression) -> BooleanExpression {
-    return BooleanExpression("ends_with", [self, suffix])
+    return BooleanExpression(functionName: "ends_with", args: [self, suffix])
   }
 
   func toLower() -> FunctionExpression {
-    return FunctionExpression("to_lower", [self])
+    return FunctionExpression(functionName: "to_lower", args: [self])
   }
 
   func toUpper() -> FunctionExpression {
-    return FunctionExpression("to_upper", [self])
+    return FunctionExpression(functionName: "to_upper", args: [self])
   }
 
-  func trim() -> FunctionExpression {
-    return FunctionExpression("trim", [self])
+  func trim(_ value: String) -> FunctionExpression {
+    return FunctionExpression(
+      functionName: "trim",
+      args: [self, Helper.sendableToExpr(value)]
+    )
+  }
+
+  func trim(_ value: Expression) -> FunctionExpression {
+    return FunctionExpression(functionName: "trim", args: [self, value])
   }
 
   func stringConcat(_ strings: [Expression]) -> FunctionExpression {
-    return FunctionExpression("string_concat", [self] + strings)
+    return FunctionExpression(functionName: "string_concat", args: [self] + strings)
   }
 
   func stringConcat(_ strings: [Sendable]) -> FunctionExpression {
     let exprs = [self] + strings.map { Helper.sendableToExpr($0) }
-    return FunctionExpression("string_concat", exprs)
+    return FunctionExpression(functionName: "string_concat", args: exprs)
   }
 
   func reverse() -> FunctionExpression {
-    return FunctionExpression("reverse", [self])
+    return FunctionExpression(functionName: "reverse", args: [self])
   }
 
   func stringReverse() -> FunctionExpression {
-    return FunctionExpression("string_reverse", [self])
+    return FunctionExpression(functionName: "string_reverse", args: [self])
   }
 
   func byteLength() -> FunctionExpression {
-    return FunctionExpression("byte_length", [self])
+    return FunctionExpression(functionName: "byte_length", args: [self])
   }
 
   func substring(position: Int, length: Int? = nil) -> FunctionExpression {
     let positionExpr = Helper.sendableToExpr(position)
     if let length = length {
-      return FunctionExpression("substring", [self, positionExpr, Helper.sendableToExpr(length)])
+      return FunctionExpression(
+        functionName: "substring",
+        args: [self, positionExpr, Helper.sendableToExpr(length)]
+      )
     } else {
-      return FunctionExpression("substring", [self, positionExpr])
+      return FunctionExpression(functionName: "substring", args: [self, positionExpr])
     }
   }
 
   func substring(position: Expression, length: Expression? = nil) -> FunctionExpression {
     if let length = length {
-      return FunctionExpression("substring", [self, position, length])
+      return FunctionExpression(functionName: "substring", args: [self, position, length])
     } else {
-      return FunctionExpression("substring", [self, position])
+      return FunctionExpression(functionName: "substring", args: [self, position])
     }
   }
 
   // --- Added Map Operations ---
 
   func mapGet(_ subfield: String) -> FunctionExpression {
-    return FunctionExpression("map_get", [self, Constant(subfield)])
+    return FunctionExpression(functionName: "map_get", args: [self, Constant(subfield)])
   }
 
   func mapRemove(_ key: String) -> FunctionExpression {
-    return FunctionExpression("map_remove", [self, Helper.sendableToExpr(key)])
+    return FunctionExpression(functionName: "map_remove", args: [self, Helper.sendableToExpr(key)])
   }
 
   func mapRemove(_ keyExpression: Expression) -> FunctionExpression {
-    return FunctionExpression("map_remove", [self, keyExpression])
+    return FunctionExpression(functionName: "map_remove", args: [self, keyExpression])
   }
 
   func mapMerge(_ maps: [[String: Sendable]]) -> FunctionExpression {
     let mapExprs = maps.map { Helper.sendableToExpr($0) }
-    return FunctionExpression("map_merge", [self] + mapExprs)
+    return FunctionExpression(functionName: "map_merge", args: [self] + mapExprs)
   }
 
   func mapMerge(_ maps: [Expression]) -> FunctionExpression {
-    return FunctionExpression("map_merge", [self] + maps)
+    return FunctionExpression(functionName: "map_merge", args: [self] + maps)
+  }
+
+  func mapSet(key: Expression, value: Sendable) -> FunctionExpression {
+    return FunctionExpression(
+      functionName: "map_set",
+      args: [self, key, Helper.sendableToExpr(value)]
+    )
+  }
+
+  func mapSet(key: String, value: Sendable) -> FunctionExpression {
+    return FunctionExpression(
+      functionName: "map_set",
+      args: [self, Helper.sendableToExpr(key), Helper.sendableToExpr(value)]
+    )
   }
 
   // --- Added Aggregate Operations (on Expr) ---
 
   func countDistinct() -> AggregateFunction {
-    return AggregateFunction("count_distinct", [self])
+    return AggregateFunction(functionName: "count_distinct", args: [self])
   }
 
   func count() -> AggregateFunction {
-    return AggregateFunction("count", [self])
+    return AggregateFunction(functionName: "count", args: [self])
   }
 
   func sum() -> AggregateFunction {
-    return AggregateFunction("sum", [self])
+    return AggregateFunction(functionName: "sum", args: [self])
   }
 
   func average() -> AggregateFunction {
-    return AggregateFunction("average", [self])
+    return AggregateFunction(functionName: "average", args: [self])
   }
 
   func minimum() -> AggregateFunction {
-    return AggregateFunction("minimum", [self])
+    return AggregateFunction(functionName: "minimum", args: [self])
   }
 
   func maximum() -> AggregateFunction {
-    return AggregateFunction("maximum", [self])
+    return AggregateFunction(functionName: "maximum", args: [self])
   }
 
   // MARK: Logical min/max
 
   func logicalMaximum(_ expressions: [Expression]) -> FunctionExpression {
-    return FunctionExpression("maximum", [self] + expressions)
+    return FunctionExpression(functionName: "maximum", args: [self] + expressions)
   }
 
   func logicalMaximum(_ values: [Sendable]) -> FunctionExpression {
     let exprs = [self] + values.map { Helper.sendableToExpr($0) }
-    return FunctionExpression("maximum", exprs)
+    return FunctionExpression(functionName: "maximum", args: exprs)
   }
 
   func logicalMinimum(_ expressions: [Expression]) -> FunctionExpression {
-    return FunctionExpression("minimum", [self] + expressions)
+    return FunctionExpression(functionName: "minimum", args: [self] + expressions)
   }
 
   func logicalMinimum(_ values: [Sendable]) -> FunctionExpression {
     let exprs = [self] + values.map { Helper.sendableToExpr($0) }
-    return FunctionExpression("minimum", exprs)
+    return FunctionExpression(functionName: "minimum", args: exprs)
   }
 
   // MARK: Vector Operations
 
   func vectorLength() -> FunctionExpression {
-    return FunctionExpression("vector_length", [self])
+    return FunctionExpression(functionName: "vector_length", args: [self])
   }
 
   func cosineDistance(_ expression: Expression) -> FunctionExpression {
-    return FunctionExpression("cosine_distance", [self, expression])
+    return FunctionExpression(functionName: "cosine_distance", args: [self, expression])
   }
 
   func cosineDistance(_ vector: VectorValue) -> FunctionExpression {
-    return FunctionExpression("cosine_distance", [self, Helper.sendableToExpr(vector)])
+    return FunctionExpression(
+      functionName: "cosine_distance",
+      args: [self, Helper.sendableToExpr(vector)]
+    )
   }
 
   func cosineDistance(_ vector: [Double]) -> FunctionExpression {
-    return FunctionExpression("cosine_distance", [self, Helper.sendableToExpr(vector)])
+    return FunctionExpression(
+      functionName: "cosine_distance",
+      args: [self, Helper.sendableToExpr(vector)]
+    )
   }
 
   func dotProduct(_ expression: Expression) -> FunctionExpression {
-    return FunctionExpression("dot_product", [self, expression])
+    return FunctionExpression(functionName: "dot_product", args: [self, expression])
   }
 
   func dotProduct(_ vector: VectorValue) -> FunctionExpression {
-    return FunctionExpression("dot_product", [self, Helper.sendableToExpr(vector)])
+    return FunctionExpression(
+      functionName: "dot_product",
+      args: [self, Helper.sendableToExpr(vector)]
+    )
   }
 
   func dotProduct(_ vector: [Double]) -> FunctionExpression {
-    return FunctionExpression("dot_product", [self, Helper.sendableToExpr(vector)])
+    return FunctionExpression(
+      functionName: "dot_product",
+      args: [self, Helper.sendableToExpr(vector)]
+    )
   }
 
   func euclideanDistance(_ expression: Expression) -> FunctionExpression {
-    return FunctionExpression("euclidean_distance", [self, expression])
+    return FunctionExpression(functionName: "euclidean_distance", args: [self, expression])
   }
 
   func euclideanDistance(_ vector: VectorValue) -> FunctionExpression {
-    return FunctionExpression("euclidean_distance", [self, Helper.sendableToExpr(vector)])
+    return FunctionExpression(
+      functionName: "euclidean_distance",
+      args: [self, Helper.sendableToExpr(vector)]
+    )
   }
 
   func euclideanDistance(_ vector: [Double]) -> FunctionExpression {
-    return FunctionExpression("euclidean_distance", [self, Helper.sendableToExpr(vector)])
+    return FunctionExpression(
+      functionName: "euclidean_distance",
+      args: [self, Helper.sendableToExpr(vector)]
+    )
   }
 
   // MARK: Timestamp operations
 
   func unixMicrosToTimestamp() -> FunctionExpression {
-    return FunctionExpression("unix_micros_to_timestamp", [self])
+    return FunctionExpression(functionName: "unix_micros_to_timestamp", args: [self])
   }
 
   func timestampToUnixMicros() -> FunctionExpression {
-    return FunctionExpression("timestamp_to_unix_micros", [self])
+    return FunctionExpression(functionName: "timestamp_to_unix_micros", args: [self])
   }
 
   func unixMillisToTimestamp() -> FunctionExpression {
-    return FunctionExpression("unix_millis_to_timestamp", [self])
+    return FunctionExpression(functionName: "unix_millis_to_timestamp", args: [self])
   }
 
   func timestampToUnixMillis() -> FunctionExpression {
-    return FunctionExpression("timestamp_to_unix_millis", [self])
+    return FunctionExpression(functionName: "timestamp_to_unix_millis", args: [self])
   }
 
   func unixSecondsToTimestamp() -> FunctionExpression {
-    return FunctionExpression("unix_seconds_to_timestamp", [self])
+    return FunctionExpression(functionName: "unix_seconds_to_timestamp", args: [self])
   }
 
   func timestampToUnixSeconds() -> FunctionExpression {
-    return FunctionExpression("timestamp_to_unix_seconds", [self])
+    return FunctionExpression(functionName: "timestamp_to_unix_seconds", args: [self])
   }
 
-  func timestampAdd(amount: Expression, unit: Expression) -> FunctionExpression {
-    return FunctionExpression("timestamp_add", [self, unit, amount])
+  func timestampTruncate(granularity: TimeUnit) -> FunctionExpression {
+    return FunctionExpression(
+      functionName: "timestamp_trunc",
+      args: [self, Helper.sendableToExpr(granularity.rawValue)]
+    )
+  }
+
+  func timestampTruncate(granularity: Sendable) -> FunctionExpression {
+    return FunctionExpression(
+      functionName: "timestamp_trunc",
+      args: [self, Helper.sendableToExpr(granularity)]
+    )
   }
 
   func timestampAdd(_ amount: Int, _ unit: TimeUnit) -> FunctionExpression {
     return FunctionExpression(
-      "timestamp_add",
-      [self, Helper.sendableToExpr(unit), Helper.sendableToExpr(amount)]
+      functionName: "timestamp_add",
+      args: [self, Helper.sendableToExpr(unit), Helper.sendableToExpr(amount)]
     )
   }
 
-  func timestampSubtract(amount: Expression, unit: Expression) -> FunctionExpression {
-    return FunctionExpression("timestamp_subtract", [self, unit, amount])
+  func timestampAdd(amount: Expression, unit: Sendable) -> FunctionExpression {
+    return FunctionExpression(
+      functionName: "timestamp_add",
+      args: [self, Helper.sendableToExpr(unit), amount]
+    )
   }
 
   func timestampSubtract(_ amount: Int, _ unit: TimeUnit) -> FunctionExpression {
     return FunctionExpression(
-      "timestamp_subtract",
-      [self, Helper.sendableToExpr(unit), Helper.sendableToExpr(amount)]
+      functionName: "timestamp_subtract",
+      args: [self, Helper.sendableToExpr(unit), Helper.sendableToExpr(amount)]
+    )
+  }
+
+  func timestampSubtract(amount: Expression, unit: Sendable) -> FunctionExpression {
+    return FunctionExpression(
+      functionName: "timestamp_subtract",
+      args: [self, Helper.sendableToExpr(unit), amount]
     )
   }
 
   func documentId() -> FunctionExpression {
-    return FunctionExpression("document_id", [self])
+    return FunctionExpression(functionName: "document_id", args: [self])
   }
 
   func collectionId() -> FunctionExpression {
-    return FunctionExpression("collection_id", [self])
+    return FunctionExpression(functionName: "collection_id", args: [self])
   }
 
   func ifError(_ catchExpression: Expression) -> FunctionExpression {
-    return FunctionExpression("if_error", [self, catchExpression])
+    return FunctionExpression(functionName: "if_error", args: [self, catchExpression])
   }
 
   func ifError(_ catchValue: Sendable) -> FunctionExpression {
-    return FunctionExpression("if_error", [self, Helper.sendableToExpr(catchValue)])
+    return FunctionExpression(
+      functionName: "if_error",
+      args: [self, Helper.sendableToExpr(catchValue)]
+    )
   }
 
   func ifAbsent(_ defaultValue: Sendable) -> FunctionExpression {
-    return FunctionExpression("if_absent", [self, Helper.sendableToExpr(defaultValue)])
+    return FunctionExpression(
+      functionName: "if_absent",
+      args: [self, Helper.sendableToExpr(defaultValue)]
+    )
   }
 
   // MARK: Sorting
@@ -910,6 +1015,6 @@ public extension Expression {
 
   func concat(_ values: [Sendable]) -> FunctionExpression {
     let exprs = [self] + values.map { Helper.sendableToExpr($0) }
-    return FunctionExpression("concat", exprs)
+    return FunctionExpression(functionName: "concat", args: exprs)
   }
 }

+ 2 - 2
Firestore/Swift/Source/Helper/PipelineHelper.swift

@@ -47,14 +47,14 @@ enum Helper {
       result.append(Constant(key))
       result.append(sendableToExpr(value))
     }
-    return FunctionExpression("map", result)
+    return FunctionExpression(functionName: "map", args: result)
   }
 
   static func array(_ elements: [Sendable?]) -> FunctionExpression {
     let transformedElements = elements.map { element in
       sendableToExpr(element)
     }
-    return FunctionExpression("array", transformedElements)
+    return FunctionExpression(functionName: "array", args: transformedElements)
   }
 
   // This function is used to convert Swift type into Objective-C type.

+ 0 - 0
Firestore/Swift/Source/SwiftAPI/Stages.swift → Firestore/Swift/Source/Stages.swift


+ 30 - 0
Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift

@@ -22,6 +22,31 @@
 import Foundation
 
 @objc public extension Firestore {
+  /// Creates a new `PipelineSource` to build and execute a data pipeline.
+  ///
+  /// A pipeline is composed of a sequence of stages. Each stage processes the
+  /// output from the previous one, and the final stage's output is the result of the
+  /// pipeline's execution.
+  ///
+  /// Example usage:
+  /// ```swift
+  /// let pipeline = firestore.pipeline()
+  ///   .collection("books")
+  ///   .where(Field("rating").isGreaterThan(4.5))
+  ///   .sort(Field("rating").descending())
+  ///   .limit(2)
+  /// ```
+  ///
+  /// Note on Execution: The stages are conceptual. The Firestore backend may
+  /// optimize execution (e.g., reordering or merging stages) as long as the
+  /// final result remains the same.
+  ///
+  /// Important Limitations:
+  /// - Pipelines operate on a request/response basis only.
+  /// - They do not utilize or update the local SDK cache.
+  /// - They do not support realtime snapshot listeners.
+  ///
+  /// - Returns: A `PipelineSource` to begin defining the pipeline's stages.
   @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
   @nonobjc func pipeline() -> PipelineSource {
     return PipelineSource(db: self) { stages, db in
@@ -29,6 +54,11 @@ import Foundation
     }
   }
 
+  /// Creates a `RealtimePipelineSource` for building and executing a realtime pipeline.
+  ///
+  /// This is an internal method and should not be used directly.
+  ///
+  /// - Returns: A `RealtimePipelineSource` for building a realtime pipeline.
   @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
   @nonobjc internal func realtimePipeline() -> RealtimePipelineSource {
     return RealtimePipelineSource(db: self) { stages, db in

+ 15 - 1
Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/AggregateFunction.swift

@@ -18,13 +18,23 @@ extension AggregateFunction {
   }
 }
 
+/// Represents an aggregate function in a pipeline.
+///
+/// An `AggregateFunction` is a function that computes a single value from a set of input values.
+///
+/// `AggregateFunction`s are typically used in the `aggregate` stage of a pipeline.
 public class AggregateFunction: AggregateBridgeWrapper, @unchecked Sendable {
   let bridge: AggregateFunctionBridge
 
   let functionName: String
   let args: [Expression]
 
-  public init(_ functionName: String, _ args: [Expression]) {
+  /// Creates a new `AggregateFunction`.
+  ///
+  /// - Parameters:
+  ///   - functionName: The name of the aggregate function.
+  ///   - args: The arguments to the aggregate function.
+  public init(functionName: String, args: [Expression]) {
     self.functionName = functionName
     self.args = args
     bridge = AggregateFunctionBridge(
@@ -34,6 +44,10 @@ public class AggregateFunction: AggregateBridgeWrapper, @unchecked Sendable {
     )
   }
 
+  /// Creates an `AliasedAggregate` from this aggregate function.
+  ///
+  /// - Parameter name: The alias for the aggregate function.
+  /// - Returns: An `AliasedAggregate` with the given alias.
   public func `as`(_ name: String) -> AliasedAggregate {
     return AliasedAggregate(aggregate: self, alias: name)
   }

+ 4 - 2
Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/AliasedAggregate.swift

@@ -12,7 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+/// An `AggregateFunction` that has been given an alias.
 public struct AliasedAggregate {
-  public let aggregate: AggregateFunction
-  public let alias: String
+  let aggregate: AggregateFunction
+
+  let alias: String
 }

+ 1 - 1
Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/CountAll.swift

@@ -38,6 +38,6 @@
 public class CountAll: AggregateFunction, @unchecked Sendable {
   /// Initializes a new `CountAll` aggregation.
   public init() {
-    super.init("count", [])
+    super.init(functionName: "count", args: [])
   }
 }

+ 4 - 0
Firestore/Swift/Source/SwiftAPI/Pipeline/DistanceMeasure.swift

@@ -20,6 +20,7 @@
 
 import Foundation
 
+/// Represents the distance measure to be used in a vector similarity search.
 public struct DistanceMeasure: Sendable, Equatable, Hashable {
   let kind: Kind
 
@@ -29,10 +30,13 @@ public struct DistanceMeasure: Sendable, Equatable, Hashable {
     case dotProduct = "dot_product"
   }
 
+  /// The Euclidean distance measure.
   public static let euclidean: DistanceMeasure = .init(kind: .euclidean)
 
+  /// The Cosine distance measure.
   public static let cosine: DistanceMeasure = .init(kind: .cosine)
 
+  /// The Dot Product distance measure.
   public static let dotProduct: DistanceMeasure = .init(kind: .dotProduct)
 
   init(kind: Kind) {

+ 1 - 0
Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/AliasedExpression.swift

@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+/// An `Expression` that has been given an alias.
 public struct AliasedExpression: Selectable, SelectableWrapper, Sendable {
   let alias: String
 

+ 204 - 161
Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Expression.swift

@@ -27,7 +27,7 @@ public protocol Expression: Sendable {
   ///
   /// ```swift
   /// // Calculate total price and alias it "totalPrice"
-  /// Field("price").multiply(Field("quantity")).`as`("totalPrice")
+  /// Field("price").multiply(Field("quantity")).as("totalPrice")
   /// ```
   ///
   /// - Parameter name: The alias to assign to this expression.
@@ -56,7 +56,7 @@ public protocol Expression: Sendable {
   /// - Returns: A new `FunctionExpression` representing the square root of the number.
   func sqrt() -> FunctionExpression
 
-  /// Creates an expression that returns the value of self raised to the power of Y.
+  /// Creates an expression that returns the value of self raised to the power of self.
   ///
   /// Returns zero on underflow.
   ///
@@ -69,7 +69,7 @@ public protocol Expression: Sendable {
   /// - Returns: A new `FunctionExpression` representing the power of the number.
   func pow(_ exponent: Sendable) -> FunctionExpression
 
-  /// Creates an expression that returns the value of self raised to the power of Y.
+  /// Creates an expression that returns the value of self raised to the power of self.
   ///
   /// Returns zero on underflow.
   ///
@@ -455,98 +455,110 @@ public protocol Expression: Sendable {
   /// Field("tags").arrayGet(Field("favoriteTagIndex"))
   /// ```
   ///
-  /// - Parameter offsetExpr: An `Expression` (evaluating to an Int) representing the offset of the
+  /// - Parameter offsetExpression: An `Expression` (evaluating to an Int) representing the offset
+  /// of the
   /// element to return.
   /// - Returns: A new `FunctionExpression` representing the "arrayGet" operation.
   func arrayGet(_ offsetExpression: Expression) -> FunctionExpression
 
-  /// Creates a `BooleanExpr` that returns `true` if this expression is greater
+  /// Creates a `BooleanExpression` that returns `true` if this expression is greater
   /// than the given expression.
   ///
   /// - Parameter other: The expression to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func greaterThan(_ other: Expression) -> BooleanExpression
 
-  /// Creates a `BooleanExpr` that returns `true` if this expression is greater
+  /// Creates a `BooleanExpression` that returns `true` if this expression is greater
   /// than the given value.
   ///
   /// - Parameter other: The value to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func greaterThan(_ other: Sendable) -> BooleanExpression
 
-  /// Creates a `BooleanExpr` that returns `true` if this expression is
+  /// Creates a `BooleanExpression` that returns `true` if this expression is
   /// greater than or equal to the given expression.
   ///
   /// - Parameter other: The expression to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func greaterThanOrEqual(_ other: Expression) -> BooleanExpression
 
-  /// Creates a `BooleanExpr` that returns `true` if this expression is
+  /// Creates a `BooleanExpression` that returns `true` if this expression is
   /// greater than or equal to the given value.
   ///
   /// - Parameter other: The value to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func greaterThanOrEqual(_ other: Sendable) -> BooleanExpression
 
-  /// Creates a `BooleanExpr` that returns `true` if this expression is less
+  /// Creates a `BooleanExpression` that returns `true` if this expression is less
   /// than the given expression.
   ///
   /// - Parameter other: The expression to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func lessThan(_ other: Expression) -> BooleanExpression
 
-  /// Creates a `BooleanExpr` that returns `true` if this expression is less
+  /// Creates a `BooleanExpression` that returns `true` if this expression is less
   /// than the given value.
   ///
   /// - Parameter other: The value to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func lessThan(_ other: Sendable) -> BooleanExpression
 
-  /// Creates a `BooleanExpr` that returns `true` if this expression is less
+  /// Creates a `BooleanExpression` that returns `true` if this expression is less
   /// than or equal to the given expression.
   ///
   /// - Parameter other: The expression to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func lessThanOrEqual(_ other: Expression) -> BooleanExpression
 
-  /// Creates a `BooleanExpr` that returns `true` if this expression is less
+  /// Creates a `BooleanExpression` that returns `true` if this expression is less
   /// than or equal to the given value.
   ///
   /// - Parameter other: The value to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func lessThanOrEqual(_ other: Sendable) -> BooleanExpression
 
-  /// Creates a `BooleanExpr` that returns `true` if this expression is equal
+  /// Creates a `BooleanExpression` that returns `true` if this expression is equal
   /// to the given expression.
   ///
   /// - Parameter other: The expression to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func equal(_ other: Expression) -> BooleanExpression
 
-  /// Creates a `BooleanExpr` that returns `true` if this expression is equal
+  /// Creates a `BooleanExpression` that returns `true` if this expression is equal
   /// to the given value.
   ///
   /// - Parameter other: The value to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func equal(_ other: Sendable) -> BooleanExpression
 
-  /// Creates a `BooleanExpr` that returns `true` if this expression is not
+  /// Creates a `BooleanExpression` that returns `true` if this expression is not
   /// equal to the given expression.
   ///
   /// - Parameter other: The expression to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func notEqual(_ other: Expression) -> BooleanExpression
 
-  /// Creates a `BooleanExpr` that returns `true` if this expression is not
+  /// Creates a `BooleanExpression` that returns `true` if this expression is not
   /// equal to the given value.
   ///
   /// - Parameter other: The value to compare against.
-  /// - Returns: A `BooleanExpr` that can be used in `where` clauses.
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func notEqual(_ other: Sendable) -> BooleanExpression
 
   /// Creates an expression that checks if this expression is equal to any of the provided
   /// expression values.
-  /// This is similar to an "IN" operator in SQL.
   ///
   /// ```swift
   /// // Check if "categoryID" field is equal to "featuredCategory" or "popularCategory" fields
@@ -554,12 +566,12 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter others: An array of at least one `Expression` value to check against.
-  /// - Returns: A new `BooleanExpr` representing the "IN" comparison (eq_any).
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func equalAny(_ others: [Expression]) -> BooleanExpression
 
   /// Creates an expression that checks if this expression is equal to any of the provided literal
   /// values.
-  /// This is similar to an "IN" operator in SQL.
   ///
   /// ```swift
   /// // Check if "category" is "Electronics", "Books", or "Home Goods"
@@ -567,12 +579,12 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter others: An array of at least one `Sendable` literal value to check against.
-  /// - Returns: A new `BooleanExpr` representing the "IN" comparison (eq_any).
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func equalAny(_ others: [Sendable]) -> BooleanExpression
 
   /// Creates an expression that checks if this expression is equal to any of the provided
   /// expression values.
-  /// This is similar to an "IN" operator in SQL.
   ///
   /// ```swift
   /// // Check if "categoryID" field is equal to any of "categoryIDs" fields
@@ -580,12 +592,12 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter arrayExpression: An `Expression` elements evaluated to be array.
-  /// - Returns: A new `BooleanExpr` representing the "IN" comparison (eq_any).
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func equalAny(_ arrayExpression: Expression) -> BooleanExpression
 
   /// Creates an expression that checks if this expression is not equal to any of the provided
   /// expression values.
-  /// This is similar to a "NOT IN" operator in SQL.
   ///
   /// ```swift
   /// // Check if "statusValue" is not equal to "archivedStatus" or "deletedStatus" fields
@@ -593,12 +605,12 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter others: An array of at least one `Expression` value to check against.
-  /// - Returns: A new `BooleanExpr` representing the "NOT IN" comparison (not_eq_any).
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func notEqualAny(_ others: [Expression]) -> BooleanExpression
 
   /// Creates an expression that checks if this expression is not equal to any of the provided
   /// literal values.
-  /// This is similar to a "NOT IN" operator in SQL.
   ///
   /// ```swift
   /// // Check if "status" is neither "pending" nor "archived"
@@ -606,12 +618,12 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter others: An array of at least one `Sendable` literal value to check against.
-  /// - Returns: A new `BooleanExpr` representing the "NOT IN" comparison (not_eq_any).
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func notEqualAny(_ others: [Sendable]) -> BooleanExpression
 
   /// Creates an expression that checks if this expression is equal to any of the provided
   /// expression values.
-  /// This is similar to an "IN" operator in SQL.
   ///
   /// ```swift
   /// // Check if "categoryID" field is not equal to any of "categoryIDs" fields
@@ -619,18 +631,18 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter arrayExpression: An `Expression` elements evaluated to be array.
-  /// - Returns: A new `BooleanExpr` representing the "IN" comparison (eq_any).
+  /// - Returns: A `BooleanExpression` that can be used in a where stage, together with other
+  /// boolean expressions.
   func notEqualAny(_ arrayExpression: Expression) -> BooleanExpression
 
   /// Creates an expression that checks if this expression evaluates to "NaN" (Not a Number).
-  /// Assumes `self` evaluates to a numeric type.
   ///
   /// ```swift
   /// // Check if the result of a calculation is NaN
   /// Field("value").divide(0).isNan()
   /// ```
   ///
-  /// - Returns: A new `BooleanExpr` representing the "isNaN" check.
+  /// - Returns: A new `BooleanExpression` representing the "isNaN" check.
   func isNan() -> BooleanExpression
 
   /// Creates an expression that checks if this expression evaluates to "Nil".
@@ -640,46 +652,38 @@ public protocol Expression: Sendable {
   /// Field("optionalField").isNil()
   /// ```
   ///
-  /// - Returns: A new `BooleanExpr` representing the "isNil" check.
+  /// - Returns: A new `BooleanExpression` representing the "isNil" check.
   func isNil() -> BooleanExpression
 
   /// Creates an expression that checks if a field exists in the document.
   ///
-  /// - Note: This typically only makes sense when `self` is a `Field` expression.
-  ///
   /// ```swift
   /// // Check if the document has a field named "phoneNumber"
   /// Field("phoneNumber").exists()
   /// ```
   ///
-  /// - Returns: A new `BooleanExpr` representing the "exists" check.
+  /// - Returns: A new `BooleanExpression` representing the "exists" check.
   func exists() -> BooleanExpression
 
   /// Creates an expression that checks if this expression produces an error during evaluation.
   ///
-  /// - Note: This API is in beta.
-  ///
   /// ```swift
   /// // Check if accessing a non-existent array index causes an error
   /// Field("myArray").arrayGet(100).isError()
   /// ```
   ///
-  /// - Returns: A new `BooleanExpr` representing the "isError" check.
+  /// - Returns: A new `BooleanExpression` representing the "isError" check.
   func isError() -> BooleanExpression
 
   /// Creates an expression that returns `true` if the result of this expression
-  /// is absent (e.g., a field does not exist in a map). Otherwise, returns `false`, even if the
-  /// value is `null`.
-  ///
-  /// - Note: This API is in beta.
-  /// - Note: This typically only makes sense when `self` is a `Field` expression.
+  /// is absent (e.g., a field does not exist in a map). Otherwise, returns `false`.
   ///
   /// ```swift
   /// // Check if the field `value` is absent.
   /// Field("value").isAbsent()
   /// ```
   ///
-  /// - Returns: A new `BooleanExpr` representing the "isAbsent" check.
+  /// - Returns: A new `BooleanExpression` representing the "isAbsent" check.
   func isAbsent() -> BooleanExpression
 
   /// Creates an expression that checks if the result of this expression is not null.
@@ -689,12 +693,11 @@ public protocol Expression: Sendable {
   /// Field("name").isNotNil()
   /// ```
   ///
-  /// - Returns: A new `BooleanExpr` representing the "isNotNil" check.
+  /// - Returns: A new `BooleanExpression` representing the "isNotNil" check.
   func isNotNil() -> BooleanExpression
 
   /// Creates an expression that checks if the results of this expression is NOT "NaN" (Not a
   /// Number).
-  /// Assumes `self` evaluates to a numeric type.
   ///
   /// ```swift
   /// // Check if the result of a calculation is NOT NaN
@@ -750,7 +753,7 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter pattern: The literal string pattern to search for. Use "%" as a wildcard.
-  /// - Returns: A new `BooleanExpr` representing the "like" comparison.
+  /// - Returns: A new `BooleanExpression` representing the "like" comparison.
   func like(_ pattern: String) -> BooleanExpression
 
   /// Creates an expression that performs a case-sensitive string comparison using wildcards against
@@ -763,14 +766,13 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter pattern: An `Expression` (evaluating to a string) representing the pattern to
-  /// search
-  /// for.
-  /// - Returns: A new `BooleanExpr` representing the "like" comparison.
+  /// search for.
+  /// - Returns: A new `BooleanExpression` representing the "like" comparison.
   func like(_ pattern: Expression) -> BooleanExpression
 
   /// Creates an expression that checks if a string (from `self`) contains a specified regular
   /// expression literal as a substring.
-  /// Uses RE2 syntax. Assumes `self` evaluates to a string.
+  /// Assumes `self` evaluates to a string.
   ///
   /// ```swift
   /// // Check if "description" contains "example" (case-insensitive)
@@ -778,12 +780,12 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter pattern: The literal string regular expression to use for the search.
-  /// - Returns: A new `BooleanExpr` representing the "regex_contains" comparison.
+  /// - Returns: A new `BooleanExpression` representing the "regex_contains" comparison.
   func regexContains(_ pattern: String) -> BooleanExpression
 
   /// Creates an expression that checks if a string (from `self`) contains a specified regular
   /// expression (from an expression) as a substring.
-  /// Uses RE2 syntax. Assumes `self` evaluates to a string, and `pattern` evaluates to a string.
+  /// Assumes `self` evaluates to a string, and `pattern` evaluates to a string.
   ///
   /// ```swift
   /// // Check if "logEntry" contains a pattern from "errorPattern" field
@@ -791,14 +793,13 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter pattern: An `Expression` (evaluating to a string) representing the regular
-  /// expression to
-  /// use for the search.
-  /// - Returns: A new `BooleanExpr` representing the "regex_contains" comparison.
+  /// expression to use for the search.
+  /// - Returns: A new `BooleanExpression` representing the "regex_contains" comparison.
   func regexContains(_ pattern: Expression) -> BooleanExpression
 
   /// Creates an expression that checks if a string (from `self`) matches a specified regular
   /// expression literal entirely.
-  /// Uses RE2 syntax. Assumes `self` evaluates to a string.
+  /// Assumes `self` evaluates to a string.
   ///
   /// ```swift
   /// // Check if the "email" field matches a valid email pattern
@@ -806,12 +807,12 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter pattern: The literal string regular expression to use for the match.
-  /// - Returns: A new `BooleanExpr` representing the regular expression match.
+  /// - Returns: A new `BooleanExpression` representing the regular expression match.
   func regexMatch(_ pattern: String) -> BooleanExpression
 
   /// Creates an expression that checks if a string (from `self`) matches a specified regular
   /// expression (from an expression) entirely.
-  /// Uses RE2 syntax. Assumes `self` evaluates to a string, and `pattern` evaluates to a string.
+  /// Assumes `self` evaluates to a string, and `pattern` evaluates to a string.
   ///
   /// ```swift
   /// // Check if "input" matches the regex stored in "validationRegex"
@@ -819,9 +820,8 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter pattern: An `Expression` (evaluating to a string) representing the regular
-  /// expression to
-  /// use for the match.
-  /// - Returns: A new `BooleanExpr` representing the regular expression match.
+  /// expression to use for the match.
+  /// - Returns: A new `BooleanExpression` representing the regular expression match.
   func regexMatch(_ pattern: Expression) -> BooleanExpression
 
   /// Creates an expression that checks if a string (from `self`) contains a specified literal
@@ -834,7 +834,7 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter substring: The literal string substring to search for.
-  /// - Returns: A new `BooleanExpr` representing the "stringContains" comparison.
+  /// - Returns: A new `BooleanExpression` representing the "stringContains" comparison.
   func stringContains(_ substring: String) -> BooleanExpression
 
   /// Creates an expression that checks if a string (from `self`) contains a specified substring
@@ -848,7 +848,7 @@ public protocol Expression: Sendable {
   ///
   /// - Parameter expression: An `Expression` (evaluating to a string) representing the substring to
   /// search for.
-  /// - Returns: A new `BooleanExpr` representing the "str_contains" comparison.
+  /// - Returns: A new `BooleanExpression` representing the "str_contains" comparison.
   func stringContains(_ expression: Expression) -> BooleanExpression
 
   /// Creates an expression that checks if a string (from `self`) starts with a given literal prefix
@@ -902,7 +902,7 @@ public protocol Expression: Sendable {
   ///
   /// - Parameter suffix: An `Expression` (evaluating to a string) representing the suffix to check
   /// for.
-  /// - Returns: A new `BooleanExpr` representing the "ends_with" comparison.
+  /// - Returns: A new `BooleanExpression` representing the "ends_with" comparison.
   func endsWith(_ suffix: Expression) -> BooleanExpression
 
   /// Creates an expression that converts a string (from `self`) to lowercase.
@@ -927,17 +927,32 @@ public protocol Expression: Sendable {
   /// - Returns: A new `FunctionExpression` representing the uppercase string.
   func toUpper() -> FunctionExpression
 
-  /// Creates an expression that removes leading and trailing whitespace from a string (from
-  /// `self`).
-  /// Assumes `self` evaluates to a string.
+  /// Creates an expression that removes leading and trailing occurrences of specified characters
+  /// from a string (from `self`).
+  /// Assumes `self` evaluates to a string, and `value` evaluates to a string.
+  ///
+  /// ```swift
+  /// // Trim leading/trailing "xy" from field
+  /// Field("code").trim(characters: "xy")
+  /// ```
+  ///
+  /// - Parameter value: A `String` containing the characters to trim.
+  /// - Returns: A new `FunctionExpression` representing the trimmed string.
+  func trim(_ value: String) -> FunctionExpression
+
+  /// Creates an expression that removes leading and trailing occurrences of specified string
+  /// (from an expression) from a string (from `self`).
+  /// Assumes `self` evaluates to a string, and `value` evaluates to a string.
   ///
   /// ```swift
-  /// // Trim whitespace from the "userInput" field
-  /// Field("userInput").trim()
+  /// // Trim characters specified by the "trimChars" field from "data"
+  /// Field("data").trim(characters: Field("trimChars"))
   /// ```
   ///
+  /// - Parameter value: An `Expression` (evaluating to a string) containing the characters to
+  /// trim.
   /// - Returns: A new `FunctionExpression` representing the trimmed string.
-  func trim() -> FunctionExpression
+  func trim(_ value: Expression) -> FunctionExpression
 
   /// Creates an expression that concatenates this string expression with other string expressions.
   /// Assumes `self` and all parameters evaluate to strings.
@@ -965,7 +980,7 @@ public protocol Expression: Sendable {
   /// - Returns: A new `FunctionExpression` representing the concatenated string.
   func stringConcat(_ strings: [Expression]) -> FunctionExpression
 
-  /// Creates an expression that reverses this string expression.
+  /// Creates an expression that reverses this expression.
   /// Assumes `self` evaluates to a string.
   ///
   /// ```swift
@@ -973,7 +988,7 @@ public protocol Expression: Sendable {
   /// Field("myString").reverse()
   /// ```
   ///
-  /// - Returns: A new `FunctionExpr` representing the reversed string.
+  /// - Returns: A new `FunctionExpression` representing the reversed string.
   func reverse() -> FunctionExpression
 
   /// Creates an expression that reverses this string expression.
@@ -984,11 +999,11 @@ public protocol Expression: Sendable {
   /// Field("myString").stringReverse()
   /// ```
   ///
-  /// - Returns: A new `FunctionExpr` representing the reversed string.
+  /// - Returns: A new `FunctionExpression` representing the reversed string.
   func stringReverse() -> FunctionExpression
 
-  /// Creates an expression that calculates the length of this string or bytes expression in bytes.
-  /// Assumes `self` evaluates to a string or bytes.
+  /// Creates an expression that calculates the length of this expression in bytes.
+  /// Assumes `self` evaluates to a string.
   ///
   /// ```swift
   /// // Calculate the length of the "myString" field in bytes.
@@ -998,48 +1013,44 @@ public protocol Expression: Sendable {
   /// Field("avatar").byteLength()
   /// ```
   ///
-  /// - Returns: A new `FunctionExpr` representing the length in bytes.
+  /// - Returns: A new `FunctionExpression` representing the length in bytes.
   func byteLength() -> FunctionExpression
 
-  /// Creates an expression that returns a substring of this expression (String or Bytes) using
+  /// Creates an expression that returns a substring of this expression using
   /// literal integers for position and optional length.
-  /// Indexing is 0-based. Assumes `self` evaluates to a string or bytes.
-  ///
-  /// - Note: This API is in beta.
+  /// Indexing is 0-based. Assumes `self` evaluates to a string.
   ///
   /// ```swift
   /// // Get substring from index 5 with length 10
   /// Field("myString").substring(5, 10)
   ///
   /// // Get substring from "myString" starting at index 3 to the end
-  /// Field("myString").substring(3, nil)
+  /// Field("myString").substring(3) // Default nil
   /// ```
   ///
   /// - Parameter position: Literal `Int` index of the first character/byte.
   /// - Parameter length: Optional literal `Int` length of the substring. If `nil`, goes to the end.
-  /// - Returns: A new `FunctionExpr` representing the substring.
+  /// - Returns: A new `FunctionExpression` representing the substring.
   func substring(position: Int, length: Int?) -> FunctionExpression
 
-  /// Creates an expression that returns a substring of this expression (String or Bytes) using
+  /// Creates an expression that returns a substring of this expression using
   /// expressions for position and optional length.
-  /// Indexing is 0-based. Assumes `self` evaluates to a string or bytes, and parameters evaluate to
+  /// Indexing is 0-based. Assumes `self` evaluates to a string, and parameters evaluate to
   /// integers.
   ///
-  /// - Note: This API is in beta.
-  ///
   /// ```swift
   /// // Get substring from index calculated by Field("start") with length from Field("len")
   /// Field("myString").substring(Field("start"), Field("len"))
   ///
   /// // Get substring from index calculated by Field("start") to the end
-  /// Field("myString").substring(Field("start"), nil) // Passing nil for optional Expr length
+  /// Field("myString").substring(Field("start")) // Default nil for optional Expression length
   /// ```
   ///
-  /// - Parameter position: An `Expr` (evaluating to an Int) for the index of the first
-  /// character/byte.
-  /// - Parameter length: Optional `Expr` (evaluating to an Int) for the length of the substring. If
-  /// `nil`, goes to the end.
-  /// - Returns: A new `FunctionExpr` representing the substring.
+  /// - Parameter position: An `Expression` (evaluating to an Int) for the index of the first
+  /// character.
+  /// - Parameter length: Optional `Expression` (evaluating to an Int) for the length of the
+  /// substring. If `nil`, goes to the end.
+  /// - Returns: A new `FunctionExpression` representing the substring.
   func substring(position: Expression, length: Expression?) -> FunctionExpression
 
   // MARK: Map Operations
@@ -1053,45 +1064,39 @@ public protocol Expression: Sendable {
   /// ```
   ///
   /// - Parameter subfield: The literal string key to access in the map.
-  /// - Returns: A new `FunctionExpr` representing the value associated with the given key.
+  /// - Returns: A new `FunctionExpression` representing the value associated with the given key.
   func mapGet(_ subfield: String) -> FunctionExpression
 
   /// Creates an expression that removes a key (specified by a literal string) from the map produced
   /// by evaluating this expression.
   /// Assumes `self` evaluates to a Map.
   ///
-  /// - Note: This API is in beta.
-  ///
   /// ```swift
   /// // Removes the key "baz" from the map held in field "myMap"
   /// Field("myMap").mapRemove("baz")
   /// ```
   ///
   /// - Parameter key: The literal string key to remove from the map.
-  /// - Returns: A new `FunctionExpr` representing the "map_remove" operation.
+  /// - Returns: A new `FunctionExpression` representing the "map_remove" operation.
   func mapRemove(_ key: String) -> FunctionExpression
 
   /// Creates an expression that removes a key (specified by an expression) from the map produced by
   /// evaluating this expression.
-  /// Assumes `self` evaluates to a Map, and `keyExpr` evaluates to a string.
-  ///
-  /// - Note: This API is in beta.
+  /// Assumes `self` evaluates to a Map, and `keyExpression` evaluates to a string.
   ///
   /// ```swift
   /// // Removes the key specified by field "keyToRemove" from the map in "settings"
   /// Field("settings").mapRemove(Field("keyToRemove"))
   /// ```
   ///
-  /// - Parameter keyExpr: An `Expr` (evaluating to a string) representing the key to remove from
-  /// the map.
-  /// - Returns: A new `FunctionExpr` representing the "map_remove" operation.
+  /// - Parameter keyExpression: An `Expression` (evaluating to a string) representing the key to
+  /// remove from the map.
+  /// - Returns: A new `FunctionExpression` representing the "map_remove" operation.
   func mapRemove(_ keyExpression: Expression) -> FunctionExpression
 
   /// Creates an expression that merges this map with multiple other map literals.
   /// Assumes `self` evaluates to a Map. Later maps overwrite keys from earlier maps.
   ///
-  /// - Note: This API is in beta.
-  ///
   /// ```swift
   /// // Merge "settings" field with { "enabled": true } and another map literal { "priority": 1 }
   /// Field("settings").mapMerge(["enabled": true], ["priority": 1])
@@ -1099,7 +1104,7 @@ public protocol Expression: Sendable {
   ///
   /// - Parameter maps: Maps (dictionary literals with `Sendable` values)
   /// to merge.
-  /// - Returns: A new `FunctionExpr` representing the "map_merge" operation.
+  /// - Returns: A new `FunctionExpression` representing the "map_merge" operation.
   func mapMerge(_ maps: [[String: Sendable]])
     -> FunctionExpression
 
@@ -1107,17 +1112,43 @@ public protocol Expression: Sendable {
   /// Assumes `self` and other arguments evaluate to Maps. Later maps overwrite keys from earlier
   /// maps.
   ///
-  /// - Note: This API is in beta.
-  ///
   /// ```swift
   /// // Merge "baseSettings" field with "userOverrides" field and "adminConfig" field
   /// Field("baseSettings").mapMerge(Field("userOverrides"), Field("adminConfig"))
   /// ```
   ///
   /// - Parameter maps: Additional `Expression` (evaluating to Maps) to merge.
-  /// - Returns: A new `FunctionExpr` representing the "map_merge" operation.
+  /// - Returns: A new `FunctionExpression` representing the "map_merge" operation.
   func mapMerge(_ maps: [Expression]) -> FunctionExpression
 
+  /// Creates an expression that adds or updates a specified field in a map.
+  /// Assumes `self` evaluates to a Map, `key` evaluates to a string, and `value` can be
+  /// any type.
+  ///
+  /// ```swift
+  /// // Set a field using a key from another field
+  /// Field("config").mapSet(key: Field("keyName"), value: Field("keyValue"))
+  /// ```
+  ///
+  /// - Parameter key: An `Expression` (evaluating to a string) representing the key of
+  /// the field to set or update.
+  /// - Parameter value: The `Expression` representing the value to set for the field.
+  /// - Returns: A new `FunctionExpression` representing the map with the updated field.
+  func mapSet(key: Expression, value: Sendable) -> FunctionExpression
+
+  /// Creates an expression that adds or updates a specified field in a map.
+  /// Assumes `self` evaluates to a Map.
+  ///
+  /// ```swift
+  /// // Set the "status" field to "active" in the "order" map
+  /// Field("order").mapSet(key: "status", value: "active")
+  /// ```
+  ///
+  /// - Parameter key: The literal string key of the field to set or update.
+  /// - Parameter value: The `Sendable` literal value to set for the field.
+  /// - Returns: A new `FunctionExpression` representing the map with the updated field.
+  func mapSet(key: String, value: Sendable) -> FunctionExpression
+
   // MARK: Aggregations
 
   /// Creates an aggregation that counts the number of distinct values of this expression.
@@ -1187,8 +1218,6 @@ public protocol Expression: Sendable {
   /// - Returns: A new `AggregateFunction` representing the "max" aggregation.
   func maximum() -> AggregateFunction
 
-  // MARK: Logical min/max
-
   /// Creates an expression that returns the larger value between this expression and other
   /// expressions, based on Firestore"s value type ordering.
   ///
@@ -1433,22 +1462,29 @@ public protocol Expression: Sendable {
   /// - Returns: A new `FunctionExpression` representing the number of seconds.
   func timestampToUnixSeconds() -> FunctionExpression
 
-  /// Creates an expression that adds a specified amount of time to this timestamp expression,
-  /// where unit and amount are provided as expressions.
-  /// Assumes `self` evaluates to a Timestamp, `unit` evaluates to a unit string, and `amount`
-  /// evaluates to an integer.
+  /// Creates an expression that truncates a timestamp to a specified granularity.
+  /// Assumes `self` evaluates to a Timestamp.
   ///
   /// ```swift
-  /// // Add duration from "unitField"/"amountField" to "timestamp"
-  /// Field("timestamp").timestampAdd(amount: Field("amountField"), unit: Field("unitField"))
+  /// // Truncate "timestamp" field to the nearest day.
+  /// Field("timestamp").timestampTruncate(granularity: .day)
   /// ```
   ///
-  /// - Parameter unit: An `Expr` evaluating to the unit of time string (e.g., "day", "hour").
-  ///                 Valid units are "microsecond", "millisecond", "second", "minute", "hour",
-  /// "day".
-  /// - Parameter amount: An `Expr` evaluating to the amount (Int) of the unit to add.
-  /// - Returns: A new "FunctionExpression" representing the resulting timestamp.
-  func timestampAdd(amount: Expression, unit: Expression) -> FunctionExpression
+  /// - Parameter granularity: A `TimeUnit` enum representing the truncation unit.
+  /// - Returns: A new `FunctionExpression` representing the truncated timestamp.
+  func timestampTruncate(granularity: TimeUnit) -> FunctionExpression
+
+  /// Creates an expression that truncates a timestamp to a specified granularity.
+  /// Assumes `self` evaluates to a Timestamp, and `granularity` is a literal string.
+  ///
+  /// ```swift
+  /// // Truncate "timestamp" field to the nearest day using a literal string.
+  /// Field("timestamp").timestampTruncate(granularity: "day")
+  /// ```
+  ///
+  /// - Parameter granularity: A `Sendable` literal string specifying the truncation unit.
+  /// - Returns: A new `FunctionExpression` representing the truncated timestamp.
+  func timestampTruncate(granularity: Sendable) -> FunctionExpression
 
   /// Creates an expression that adds a specified amount of time to this timestamp expression,
   /// where unit and amount are provided as literals.
@@ -1464,27 +1500,25 @@ public protocol Expression: Sendable {
   /// - Returns: A new "FunctionExpression" representing the resulting timestamp.
   func timestampAdd(_ amount: Int, _ unit: TimeUnit) -> FunctionExpression
 
-  /// Creates an expression that subtracts a specified amount of time from this timestamp
-  /// expression,
-  /// where unit and amount are provided as expressions.
-  /// Assumes `self` evaluates to a Timestamp, `unit` evaluates to a unit string, and `amount`
-  /// evaluates to an integer.
+  /// Creates an expression that adds a specified amount of time to this timestamp expression,
+  /// where unit and amount are provided as an expression for amount and a literal for unit.
+  /// Assumes `self` evaluates to a Timestamp, `amount` evaluates to an integer, and `unit`
+  /// evaluates to a string.
   ///
   /// ```swift
-  /// // Subtract duration from "unitField"/"amountField" from "timestamp"
-  /// Field("timestamp").timestampSubtract(amount: Field("amountField"), unit: Field("unitField"))
+  /// // Add duration from "amountField" to "timestamp" with a literal unit "day".
+  /// Field("timestamp").timestampAdd(amount: Field("amountField"), unit: "day")
   /// ```
   ///
-  /// - Parameter unit: An `Expression` evaluating to the unit of time string (e.g., "day", "hour").
+  /// - Parameter unit: A `Sendable` literal string specifying the unit of time.
   ///                 Valid units are "microsecond", "millisecond", "second", "minute", "hour",
   /// "day".
-  /// - Parameter amount: An `Expression` evaluating to the amount (Int) of the unit to subtract.
+  /// - Parameter amount: An `Expression` evaluating to the amount (Int) of the unit to add.
   /// - Returns: A new "FunctionExpression" representing the resulting timestamp.
-  func timestampSubtract(amount: Expression, unit: Expression) -> FunctionExpression
+  func timestampAdd(amount: Expression, unit: Sendable) -> FunctionExpression
 
   /// Creates an expression that subtracts a specified amount of time from this timestamp
-  /// expression,
-  /// where unit and amount are provided as literals.
+  /// expression, where unit and amount are provided as literals.
   /// Assumes `self` evaluates to a Timestamp.
   ///
   /// ```swift
@@ -1497,9 +1531,25 @@ public protocol Expression: Sendable {
   /// - Returns: A new "FunctionExpression" representing the resulting timestamp.
   func timestampSubtract(_ amount: Int, _ unit: TimeUnit) -> FunctionExpression
 
-  /// Creates an expression that returns the document ID from a path.
+  /// Creates an expression that subtracts a specified amount of time from this timestamp
+  /// expression, where unit and amount are provided as an expression for amount and a literal for
+  /// unit.
+  /// Assumes `self` evaluates to a Timestamp, `amount` evaluates to an integer, and `unit`
+  /// evaluates to a string.
   ///
-  /// - Note: This API is in beta.
+  /// ```swift
+  /// // Subtract duration from "amountField" from "timestamp" with a literal unit "day".
+  /// Field("timestamp").timestampSubtract(amount: Field("amountField"), unit: "day")
+  /// ```
+  ///
+  /// - Parameter unit: A `Sendable` literal string specifying the unit of time.
+  ///                 Valid units are "microsecond", "millisecond", "second", "minute", "hour",
+  /// "day".
+  /// - Parameter amount: An `Expression` evaluating to the amount (Int) of the unit to subtract.
+  /// - Returns: A new "FunctionExpression" representing the resulting timestamp.
+  func timestampSubtract(amount: Expression, unit: Sendable) -> FunctionExpression
+
+  /// Creates an expression that returns the document ID from a path.
   ///
   /// ```swift
   /// // Get the document ID from a path.
@@ -1514,26 +1564,21 @@ public protocol Expression: Sendable {
   /// root itself.
   func collectionId() -> FunctionExpression
 
-  /// Creates an expression that returns the result of `catchExpr` if this expression produces an
-  /// error during evaluation,
-  /// otherwise returns the result of this expression.
-  ///
-  /// - Note: This API is in beta.
+  /// Creates an expression that returns the result of `catchExpression` if this expression produces
+  /// an error during evaluation, otherwise returns the result of this expression.
   ///
   /// ```swift
   /// // Try dividing "a" by "b", return field "fallbackValue" on error (e.g., division by zero)
   /// Field("a").divide(Field("b")).ifError(Field("fallbackValue"))
   /// ```
   ///
-  /// - Parameter catchExpr: The `Expression` to evaluate and return if this expression errors.
+  /// - Parameter catchExpression: The `Expression` to evaluate and return if this expression
+  /// errors.
   /// - Returns: A new "FunctionExpression" representing the "ifError" operation.
-  func ifError(_ catchExpr: Expression) -> FunctionExpression
+  func ifError(_ catchExpression: Expression) -> FunctionExpression
 
   /// Creates an expression that returns the literal `catchValue` if this expression produces an
-  /// error during evaluation,
-  /// otherwise returns the result of this expression.
-  ///
-  /// - Note: This API is in beta.
+  /// error during evaluation, otherwise returns the result of this expression.
   ///
   /// ```swift
   /// // Get first item in "title" array, or return "Default Title" if error (e.g., empty array)
@@ -1548,8 +1593,6 @@ public protocol Expression: Sendable {
   /// absent (e.g., a field does not exist in a map).
   /// Otherwise, returns the result of this expression.
   ///
-  /// - Note: This API is in beta.
-  ///
   /// ```swift
   /// // If the "optionalField" is absent, return "default value".
   /// Field("optionalField").ifAbsent("default value")

+ 5 - 1
Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Field.swift

@@ -12,7 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-///
 /// A `Field` is an `Expression` that represents a field in a Firestore document.
 ///
 /// It is a central component for building queries and transformations in Firestore pipelines.
@@ -42,9 +41,12 @@ public struct Field: Expression, Selectable, BridgeWrapper, SelectableWrapper,
     return self
   }
 
+  /// The name of the field.
   public let fieldName: String
 
   /// Creates a new `Field` expression from a field name.
+  ///
+  /// - Parameter name: The name of the field.
   public init(_ name: String) {
     let fieldBridge = FieldBridge(name: name)
     bridge = fieldBridge
@@ -53,6 +55,8 @@ public struct Field: Expression, Selectable, BridgeWrapper, SelectableWrapper,
   }
 
   /// Creates a new `Field` expression from a `FieldPath`.
+  ///
+  /// - Parameter path: The `FieldPath` of the field.
   public init(_ path: FieldPath) {
     let fieldBridge = FieldBridge(path: path)
     bridge = fieldBridge

+ 1 - 1
Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ArrayExpression.swift

@@ -38,6 +38,6 @@ public class ArrayExpression: FunctionExpression, @unchecked Sendable {
       result.append(Helper.sendableToExpr(element))
     }
 
-    super.init("array", result)
+    super.init(functionName: "array", args: result)
   }
 }

+ 12 - 9
Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/BooleanExpression.swift

@@ -31,8 +31,8 @@ import Foundation
 ///   )
 /// ```
 public class BooleanExpression: FunctionExpression, @unchecked Sendable {
-  override public init(_ functionName: String, _ agrs: [Expression]) {
-    super.init(functionName, agrs)
+  override public init(functionName: String, args: [Expression]) {
+    super.init(functionName: functionName, args: args)
   }
 
   /// Creates an aggregation that counts the number of documents for which this boolean expression
@@ -52,8 +52,8 @@ public class BooleanExpression: FunctionExpression, @unchecked Sendable {
   /// ```
   ///
   /// - Returns: An `AggregateFunction` that performs the conditional count.
-  func countIf() -> AggregateFunction {
-    return AggregateFunction("count_if", [self])
+  public func countIf() -> AggregateFunction {
+    return AggregateFunction(functionName: "count_if", args: [self])
   }
 
   /// Creates a conditional expression that returns one of two specified expressions based on the
@@ -79,7 +79,10 @@ public class BooleanExpression: FunctionExpression, @unchecked Sendable {
   /// - Returns: A new `FunctionExpression` representing the conditional logic.
   public func then(_ thenExpression: Expression,
                    else elseExpression: Expression) -> FunctionExpression {
-    return FunctionExpression("conditional", [self, thenExpression, elseExpression])
+    return FunctionExpression(
+      functionName: "conditional",
+      args: [self, thenExpression, elseExpression]
+    )
   }
 
   /// Combines two boolean expressions with a logical AND (`&&`).
@@ -103,7 +106,7 @@ public class BooleanExpression: FunctionExpression, @unchecked Sendable {
   public static func && (lhs: BooleanExpression,
                          rhs: @autoclosure () throws -> BooleanExpression) rethrows
     -> BooleanExpression {
-    try BooleanExpression("and", [lhs, rhs()])
+    try BooleanExpression(functionName: "and", args: [lhs, rhs()])
   }
 
   /// Combines two boolean expressions with a logical OR (`||`).
@@ -127,7 +130,7 @@ public class BooleanExpression: FunctionExpression, @unchecked Sendable {
   public static func || (lhs: BooleanExpression,
                          rhs: @autoclosure () throws -> BooleanExpression) rethrows
     -> BooleanExpression {
-    try BooleanExpression("or", [lhs, rhs()])
+    try BooleanExpression(functionName: "or", args: [lhs, rhs()])
   }
 
   /// Combines two boolean expressions with a logical XOR (`^`).
@@ -151,7 +154,7 @@ public class BooleanExpression: FunctionExpression, @unchecked Sendable {
   public static func ^ (lhs: BooleanExpression,
                         rhs: @autoclosure () throws -> BooleanExpression) rethrows
     -> BooleanExpression {
-    try BooleanExpression("xor", [lhs, rhs()])
+    try BooleanExpression(functionName: "xor", args: [lhs, rhs()])
   }
 
   /// Negates a boolean expression with a logical NOT (`!`).
@@ -168,6 +171,6 @@ public class BooleanExpression: FunctionExpression, @unchecked Sendable {
   /// - Parameter lhs: The boolean expression to negate.
   /// - Returns: A new `BooleanExpression` representing the logical NOT.
   public static prefix func ! (lhs: BooleanExpression) -> BooleanExpression {
-    return BooleanExpression("not", [lhs])
+    return BooleanExpression(functionName: "not", args: [lhs])
   }
 }

+ 2 - 2
Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ConditionalExpression.swift

@@ -41,9 +41,9 @@ public class ConditionalExpression: FunctionExpression, @unchecked Sendable {
   ///   - expression: The `BooleanExpression` to evaluate.
   ///   - thenExpression: The `Expression` to evaluate if the boolean expression is `true`.
   ///   - elseExpression: The `Expression` to evaluate if the boolean expression is `false`.
-  public init(_ expr: BooleanExpression,
+  public init(_ expression: BooleanExpression,
               then thenExpression: Expression,
               else elseExpression: Expression) {
-    super.init("conditional", [expr, thenExpression, elseExpression])
+    super.init(functionName: "conditional", args: [expression, thenExpression, elseExpression])
   }
 }

+ 1 - 1
Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/CurrentTimestamp.swift

@@ -25,6 +25,6 @@ import Foundation
 /// ```
 public class CurrentTimestamp: FunctionExpression, @unchecked Sendable {
   public init() {
-    super.init("current_timestamp", [])
+    super.init(functionName: "current_timestamp", args: [])
   }
 }

+ 1 - 1
Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ErrorExpression.swift

@@ -23,6 +23,6 @@ import Foundation
 /// ```
 public class ErrorExpression: FunctionExpression, @unchecked Sendable {
   public init(_ errorMessage: String) {
-    super.init("error", [Constant(errorMessage)])
+    super.init(functionName: "error", args: [Constant(errorMessage)])
   }
 }

+ 16 - 4
Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/FunctionExpression.swift

@@ -12,18 +12,30 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+/// Represents a function call in a pipeline.
+///
+/// A `FunctionExpression` is an expression that represents a function call with a given name and
+/// arguments.
+///
+/// `FunctionExpression`s are typically used to perform operations on data in a pipeline, such as
+/// mathematical calculations, string manipulations, or array operations.
 public class FunctionExpression: Expression, BridgeWrapper, @unchecked Sendable {
   let bridge: ExprBridge
 
   let functionName: String
-  let agrs: [Expression]
+  let args: [Expression]
 
-  public init(_ functionName: String, _ agrs: [Expression]) {
+  /// Creates a new `FunctionExpression`.
+  ///
+  /// - Parameters:
+  ///   - functionName: The name of the function.
+  ///   - args: The arguments to the function.
+  public init(functionName: String, args: [Expression]) {
     self.functionName = functionName
-    self.agrs = agrs
+    self.args = args
     bridge = FunctionExprBridge(
       name: functionName,
-      args: self.agrs.map { $0.toBridge()
+      args: self.args.map { $0.toBridge()
       }
     )
   }

+ 1 - 1
Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/MapExpression.swift

@@ -36,6 +36,6 @@ public class MapExpression: FunctionExpression, @unchecked Sendable {
       result.append(Helper.sendableToExpr(element.value))
     }
 
-    super.init("map", result)
+    super.init(functionName: "map", args: result)
   }
 }

+ 3 - 3
Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/RandomExpression.swift

@@ -26,9 +26,9 @@
 ///   .collection("users")
 ///   .where(RandomExpression().lessThan(0.1))
 /// ```
-public class RandomExpression: FunctionExpression, @unchecked Sendable {
+class RandomExpression: FunctionExpression, @unchecked Sendable {
   /// Creates a new `RandomExpression` that generates a random number.
-  public init() {
-    super.init("rand", [])
+  init() {
+    super.init(functionName: "rand", args: [])
   }
 }

+ 7 - 0
Firestore/Swift/Source/SwiftAPI/Pipeline/Ordering.swift

@@ -14,9 +14,13 @@
  * limitations under the License.
  */
 
+/// An ordering for the documents in a pipeline.
 public struct Ordering: @unchecked Sendable {
+  /// The expression to order by.
   public let expression: Expression
+  /// The direction to order in.
   public let direction: Direction
+
   let bridge: OrderingBridge
 
   init(expression: Expression, direction: Direction) {
@@ -26,6 +30,7 @@ public struct Ordering: @unchecked Sendable {
   }
 }
 
+/// A direction to order results in.
 public struct Direction: Sendable, Equatable, Hashable {
   let kind: Kind
   public let rawValue: String
@@ -35,8 +40,10 @@ public struct Direction: Sendable, Equatable, Hashable {
     case descending
   }
 
+  /// The ascending direction.
   static let ascending = Direction(kind: .ascending, rawValue: "ascending")
 
+  /// The descending direction.
   static let descending = Direction(kind: .descending, rawValue: "descending")
 
   init(kind: Kind, rawValue: String) {

+ 13 - 17
Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift

@@ -24,16 +24,11 @@ import Foundation
 ///
 /// A pipeline takes data sources, such as Firestore collections or collection groups, and applies
 /// a series of stages that are chained together. Each stage takes the output from the previous
-/// stage
-/// (or the data source) and produces an output for the next stage (or as the final output of the
-/// pipeline).
+/// stage (or the data source) and produces an output for the next stage (or as the final output of
+/// the pipeline).
 ///
 /// Expressions can be used within each stage to filter and transform data through the stage.
 ///
-/// NOTE: The chained stages do not prescribe exactly how Firestore will execute the pipeline.
-/// Instead, Firestore only guarantees that the result is the same as if the chained stages were
-/// executed in order.
-///
 /// ## Usage Examples
 ///
 /// The following examples assume you have a `Firestore` instance named `db`.
@@ -88,6 +83,7 @@ public struct Pipeline: @unchecked Sendable {
     bridge = PipelineBridge(stages: stages.map { $0.bridge }, db: db)
   }
 
+  /// A `Pipeline.Snapshot` contains the results of a pipeline execution.
   public struct Snapshot: Sendable {
     /// An array of all the results in the `Pipeline.Snapshot`.
     public let results: [PipelineResult]
@@ -114,8 +110,8 @@ public struct Pipeline: @unchecked Sendable {
   /// // let pipeline: Pipeline = ... // Assume a pipeline is already configured.
   /// do {
   ///   let snapshot = try await pipeline.execute()
-  ///   // Process snapshot.documents
-  ///   print("Pipeline executed successfully: \(snapshot.documents)")
+  ///   // Process snapshot.results
+  ///   print("Pipeline executed successfully: \(snapshot.results)")
   /// } catch {
   ///   print("Pipeline execution failed: \(error)")
   /// }
@@ -305,7 +301,7 @@ public struct Pipeline: @unchecked Sendable {
   /// // let pipeline: Pipeline = ... // Assume initial pipeline.
   /// // Limit results to the top 10 highest-rated books.
   /// let topTenPipeline = pipeline
-  ///                      .sort(Descending(Field("rating")))
+  ///                      .sort([Field("rating").descending()])
   ///                      .limit(10)
   /// // let results = try await topTenPipeline.execute()
   /// ```
@@ -324,7 +320,7 @@ public struct Pipeline: @unchecked Sendable {
   /// ```swift
   /// // let pipeline: Pipeline = ... // Assume initial pipeline.
   /// // Get a list of unique author and genre combinations.
-  /// let distinctAuthorsGenresPipeline = pipeline.distinct("author", "genre")
+  /// let distinctAuthorsGenresPipeline = pipeline.distinct(["author", "genre"])
   /// // To further select only the author:
   /// //   .select("author")
   /// // let results = try await distinctAuthorsGenresPipeline.execute()
@@ -379,11 +375,11 @@ public struct Pipeline: @unchecked Sendable {
   /// // let pipeline: Pipeline = ... // Assume pipeline from "books" collection.
   /// // Calculate the average rating for each genre.
   /// let groupedAggregationPipeline = pipeline.aggregate(
-  ///   [AggregateWithas(aggregate: average(Field("rating")), alias: "avg_rating")],
+  ///   [Field("rating").average().as("avg_rating")],
   ///   groups: [Field("genre")] // Group by the "genre" field.
   /// )
   /// // let results = try await groupedAggregationPipeline.execute()
-  /// // results.documents might be:
+  /// // snapshot.results might be:
   /// // [
   /// //   ["genre": "SciFi", "avg_rating": 4.5],
   /// //   ["genre": "Fantasy", "avg_rating": 4.2]
@@ -486,8 +482,8 @@ public struct Pipeline: @unchecked Sendable {
   ///
   /// - Parameter expression: The `Expr` (typically a `Field`) that resolves to the nested map.
   /// - Returns: A new `Pipeline` object with this stage appended.
-  public func replace(with expr: Expression) -> Pipeline {
-    return Pipeline(stages: stages + [ReplaceWith(expr: expr)], db: db)
+  public func replace(with expression: Expression) -> Pipeline {
+    return Pipeline(stages: stages + [ReplaceWith(expr: expression)], db: db)
   }
 
   /// Fully overwrites document fields with those from a nested map identified by a field name.
@@ -566,7 +562,7 @@ public struct Pipeline: @unchecked Sendable {
   /// // Field("topic").as("category")])
   ///
   /// // Emit documents from both "books" and "magazines" collections.
-  /// let combinedPipeline = booksPipeline.union(with: [magazinesPipeline])
+  /// let combinedPipeline = booksPipeline.union(with: magazinesPipeline)
   /// // let results = try await combinedPipeline.execute()
   /// ```
   ///
@@ -625,7 +621,7 @@ public struct Pipeline: @unchecked Sendable {
   /// the caller must ensure correct name, order, and types.
   ///
   /// Parameters in `params` and `options` are typically primitive types, `Field`,
-  /// `Function`, `Expr`, or arrays/dictionaries thereof.
+  /// `Function`, `Expression`, or arrays/dictionaries thereof.
   ///
   /// ```swift
   /// // let pipeline: Pipeline = ...

+ 33 - 0
Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift

@@ -12,6 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+/// A `PipelineSource` is the entry point for building a Firestore pipeline. It allows you to
+/// specify the source of the data for the pipeline, which can be a collection, a collection group,
+/// a list of documents, or the entire database.
 @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
 public struct PipelineSource: @unchecked Sendable {
   let db: Firestore
@@ -22,14 +25,26 @@ public struct PipelineSource: @unchecked Sendable {
     self.factory = factory
   }
 
+  /// Specifies a collection as the data source for the pipeline.
+  ///
+  /// - Parameter path: The path to the collection.
+  /// - Returns: A `Pipeline` with the specified collection as its source.
   public func collection(_ path: String) -> Pipeline {
     return factory([CollectionSource(collection: db.collection(path), db: db)], db)
   }
 
+  /// Specifies a collection as the data source for the pipeline.
+  ///
+  /// - Parameter coll: The `CollectionReference` of the collection.
+  /// - Returns: A `Pipeline` with the specified collection as its source.
   public func collection(_ coll: CollectionReference) -> Pipeline {
     return factory([CollectionSource(collection: coll, db: db)], db)
   }
 
+  /// Specifies a collection group as the data source for the pipeline.
+  ///
+  /// - Parameter collectionId: The ID of the collection group.
+  /// - Returns: A `Pipeline` with the specified collection group as its source.
   public func collectionGroup(_ collectionId: String) -> Pipeline {
     return factory(
       [CollectionGroupSource(collectionId: collectionId)],
@@ -37,19 +52,37 @@ public struct PipelineSource: @unchecked Sendable {
     )
   }
 
+  /// Specifies the entire database as the data source for the pipeline.
+  ///
+  /// - Returns: A `Pipeline` with the entire database as its source.
   public func database() -> Pipeline {
     return factory([DatabaseSource()], db)
   }
 
+  /// Specifies a list of documents as the data source for the pipeline.
+  ///
+  /// - Parameter docs: An array of `DocumentReference` objects.
+  /// - Returns: A `Pipeline` with the specified documents as its source.
   public func documents(_ docs: [DocumentReference]) -> Pipeline {
     return factory([DocumentsSource(docs: docs, db: db)], db)
   }
 
+  /// Specifies a list of documents as the data source for the pipeline.
+  ///
+  /// - Parameter paths: An array of document paths.
+  /// - Returns: A `Pipeline` with the specified documents as its source.
   public func documents(_ paths: [String]) -> Pipeline {
     let docs = paths.map { db.document($0) }
     return factory([DocumentsSource(docs: docs, db: db)], db)
   }
 
+  /// Creates a `Pipeline` from an existing `Query`.
+  ///
+  /// This allows you to convert a standard Firestore query into a pipeline, which can then be
+  /// further modified with additional pipeline stages.
+  ///
+  /// - Parameter query: The `Query` to convert into a pipeline.
+  /// - Returns: A `Pipeline` that is equivalent to the given query.
   public func create(from query: Query) -> Pipeline {
     let stageBridges = PipelineBridge.createStageBridges(from: query)
     let stages: [Stage] = stageBridges.map { bridge in

+ 8 - 0
Firestore/Swift/Source/SwiftAPI/Pipeline/Selectable.swift

@@ -12,4 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+/// A protocol for expressions that have a name.
+///
+/// `Selectable` is adopted by expressions that can be used in pipeline stages where a named output
+/// is required, such as `select` and `distinct`.
+///
+/// A `Field` is a `Selectable` where the name is the field path.
+///
+/// An expression can be made `Selectable` by giving it an alias using the `.as()` method.
 public protocol Selectable: Sendable {}

+ 3 - 3
Firestore/Swift/Tests/Integration/PipelineApiTests.swift

@@ -403,12 +403,12 @@ final class PipelineApiTests: FSTIntegrationTestCase {
 
   func testGeneric() async throws {
     // This is the same of the logicalMin('price', 0)', if it did not exist
-    _ = FunctionExpression("logicalMin", [Field("price"), Constant(0)])
+    _ = FunctionExpression(functionName: "logicalMin", args: [Field("price"), Constant(0)])
 
     // Create a generic BooleanExpr for use where BooleanExpr is required
-    _ = BooleanExpression("eq", [Field("price"), Constant(10)])
+    _ = BooleanExpression(functionName: "eq", args: [Field("price"), Constant(10)])
 
     // Create a generic AggregateFunction for use where AggregateFunction is required
-    _ = AggregateFunction("sum", [Field("price")])
+    _ = AggregateFunction(functionName: "sum", args: [Field("price")])
   }
 }

+ 326 - 252
Firestore/Swift/Tests/Integration/PipelineTests.swift

@@ -849,27 +849,26 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
     }
   }
 
-  // Hide this test due to `.countIf()` design is incomplete.
-//  func testReturnsCountIfAccumulation() async throws {
-//    let collRef = collectionRef(withDocuments: bookDocs)
-//    let db = collRef.firestore
-//
-//    let expectedCount = 3
-//    let expectedResults: [String: Sendable] = ["count": expectedCount]
-//    let condition = Field("rating").greaterThan(4.3)
-//
-//    let pipeline = db.pipeline()
-//      .collection(collRef.path)
-//      .aggregate([condition.countIf().as("count")])
-//    let snapshot = try await pipeline.execute()
-//
-//    XCTAssertEqual(snapshot.results.count, 1, "countIf aggregate should return a single document")
-//    if let result = snapshot.results.first {
-//      TestHelper.compare(pipelineResult: result, expected: expectedResults)
-//    } else {
-//      XCTFail("No result for countIf aggregation")
-//    }
-//  }
+  func testReturnsCountIfAccumulation() async throws {
+    let collRef = collectionRef(withDocuments: bookDocs)
+    let db = collRef.firestore
+
+    let expectedCount = 3
+    let expectedResults: [String: Sendable] = ["count": expectedCount]
+    let condition = Field("rating").greaterThan(4.3)
+
+    let pipeline = db.pipeline()
+      .collection(collRef.path)
+      .aggregate([condition.countIf().as("count")])
+    let snapshot = try await pipeline.execute()
+
+    XCTAssertEqual(snapshot.results.count, 1, "countIf aggregate should return a single document")
+    if let result = snapshot.results.first {
+      TestHelper.compare(pipelineResult: result, expected: expectedResults)
+    } else {
+      XCTFail("No result for countIf aggregation")
+    }
+  }
 
   func testDistinctStage() async throws {
     let collRef = collectionRef(withDocuments: bookDocs)
@@ -1701,25 +1700,6 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
     TestHelper.compare(snapshot: snapshot, expected: expectedResults, enforceOrder: true)
   }
 
-//  func testEquivalentWorks() async throws {
-//    let collRef = collectionRef(withDocuments: [
-//      "doc1": ["value": 1, "value2": 1],
-//      "doc2": ["value": 1, "value2": 2],
-//      "doc3": ["value": NSNull(), "value2": NSNull()],
-//      "doc4": ["value": NSNull(), "value2": 1],
-//      "doc5": ["value": Double.nan, "value2": Double.nan],
-//      "doc6": ["value": Double.nan, "value2": 1],
-//    ])
-//    let db = collRef.firestore
-//
-//    let pipeline = db.pipeline()
-//      .collection(collRef.path)
-//      .where(Field("value").equivalent(Field("value2")))
-//    let snapshot = try await pipeline.execute()
-//
-//    XCTAssertEqual(snapshot.results.count, 3)
-//  }
-
   func testInWorks() async throws {
     let collRef = collectionRef(withDocuments: bookDocs)
     let db = collRef.firestore
@@ -2405,9 +2385,12 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
         Field("value").exp().as("expValue"),
       ])
 
-    let snapshot = try await pipeline.execute()
-    XCTAssertEqual(snapshot.results.count, 1)
-    XCTAssertNil(snapshot.results.first!.get("expValue"))
+    do {
+      let _ = try await pipeline.execute()
+      XCTFail("The pipeline should have thrown an error, but it did not.")
+    } catch {
+      XCTAssert(true, "Successfully caught expected error from exponent overflow.")
+    }
   }
 
   func testCollectionIdWorks() async throws {
@@ -2499,8 +2482,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
     let collRef = collectionRef(withDocuments: bookDocs)
     let db = collRef.firestore
 
-    // Part 1
-    var pipeline = db.pipeline()
+    let pipeline = db.pipeline()
       .collection(collRef.path)
       .sort([Field("rating").descending()])
       .limit(1)
@@ -2508,8 +2490,6 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
         [
           Field("rating").isNil().as("ratingIsNull"),
           Field("rating").isNan().as("ratingIsNaN"),
-          Field("title").arrayGet(0).isError().as("isError"),
-          Field("title").arrayGet(0).ifError(Constant("was error")).as("ifError"),
           Field("foo").isAbsent().as("isAbsent"),
           Field("title").isNotNil().as("titleIsNotNull"),
           Field("cost").isNotNan().as("costIsNotNan"),
@@ -2518,15 +2498,13 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
         ]
       )
 
-    var snapshot = try await pipeline.execute()
-    XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document for checks part 1")
+    let snapshot = try await pipeline.execute()
+    XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document for checks")
 
     if let resultDoc = snapshot.results.first {
       let expectedResults: [String: Sendable?] = [
         "ratingIsNull": false,
         "ratingIsNaN": false,
-        "isError": true,
-        "ifError": "was error",
         "isAbsent": true,
         "titleIsNotNull": true,
         "costIsNotNan": false,
@@ -2535,42 +2513,61 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
       ]
       TestHelper.compare(pipelineResult: resultDoc, expected: expectedResults)
     } else {
-      XCTFail("No document retrieved for checks part 1")
+      XCTFail("No document retrieved for checks")
     }
+  }
 
-    // Part 2
-    pipeline = db.pipeline()
+  func testIsError() async throws {
+    let collRef = collectionRef(withDocuments: bookDocs)
+    let db = collRef.firestore
+
+    let pipeline = db.pipeline()
       .collection(collRef.path)
       .sort([Field("rating").descending()])
       .limit(1)
       .select(
         [
-          Field("rating").isNil().as("ratingIsNull"),
-          Field("rating").isNan().as("ratingIsNaN"),
-          Field("title").arrayGet(0).isError().as("isError"),
-          Field("title").arrayGet(0).ifError(Constant("was error")).as("ifError"),
-          Field("foo").isAbsent().as("isAbsent"),
-          Field("title").isNotNil().as("titleIsNotNull"),
-          Field("cost").isNotNan().as("costIsNotNan"),
+          Field("title").arrayLength().isError().as("isError"),
         ]
       )
 
-    snapshot = try await pipeline.execute()
-    XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document for checks part 2")
+    let snapshot = try await pipeline.execute()
+    XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document for test")
 
     if let resultDoc = snapshot.results.first {
       let expectedResults: [String: Sendable?] = [
-        "ratingIsNull": false,
-        "ratingIsNaN": false,
         "isError": true,
+      ]
+      TestHelper.compare(pipelineResult: resultDoc, expected: expectedResults)
+    } else {
+      XCTFail("No document retrieved for test")
+    }
+  }
+
+  func testIfError() async throws {
+    let collRef = collectionRef(withDocuments: bookDocs)
+    let db = collRef.firestore
+
+    let pipeline = db.pipeline()
+      .collection(collRef.path)
+      .sort([Field("rating").descending()])
+      .limit(1)
+      .select(
+        [
+          Field("title").arrayLength().ifError(Constant("was error")).as("ifError"),
+        ]
+      )
+
+    let snapshot = try await pipeline.execute()
+    XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document for test")
+
+    if let resultDoc = snapshot.results.first {
+      let expectedResults: [String: Sendable?] = [
         "ifError": "was error",
-        "isAbsent": true,
-        "titleIsNotNull": true,
-        "costIsNotNan": false,
       ]
       TestHelper.compare(pipelineResult: resultDoc, expected: expectedResults)
     } else {
-      XCTFail("No document retrieved for checks part 2")
+      XCTFail("No document retrieved for test")
     }
   }
 
@@ -2758,7 +2755,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
       .limit(1)
       .select(
         [
-          FunctionExpression("add", [Field("rating"), Constant(1)]).as(
+          FunctionExpression(functionName: "add", args: [Field("rating"), Constant(1)]).as(
             "rating"
           ),
         ]
@@ -2786,9 +2783,9 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
     let pipeline = db.pipeline()
       .collection(collRef.path)
       .where(
-        BooleanExpression("and", [Field("rating").greaterThan(0),
-                                  Field("title").charLength().lessThan(5),
-                                  Field("tags").arrayContains("propaganda")])
+        BooleanExpression(functionName: "and", args: [Field("rating").greaterThan(0),
+                                                      Field("title").charLength().lessThan(5),
+                                                      Field("tags").arrayContains("propaganda")])
       )
       .select(["title"])
 
@@ -2810,8 +2807,8 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
     let pipeline = db.pipeline()
       .collection(collRef.path)
       .where(BooleanExpression(
-        "array_contains_any",
-        [Field("tags"), ArrayExpression(["politics"])]
+        functionName: "array_contains_any",
+        args: [Field("tags"), ArrayExpression(["politics"])]
       ))
       .select([Field("title")])
 
@@ -2832,8 +2829,13 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
 
     let pipeline = db.pipeline()
       .collection(collRef.path)
-      .aggregate([AggregateFunction("count_if", [Field("rating").greaterThanOrEqual(4.5)])
-          .as("countOfBest")])
+      .aggregate(
+        [AggregateFunction(
+          functionName: "count_if",
+          args: [Field("rating").greaterThanOrEqual(4.5)]
+        )
+        .as("countOfBest")]
+      )
 
     let snapshot = try await pipeline.execute()
 
@@ -2858,7 +2860,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
       .collection(collRef.path)
       .sort(
         [
-          FunctionExpression("char_length", [Field("title")]).ascending(),
+          FunctionExpression(functionName: "char_length", args: [Field("title")]).ascending(),
           Field("__name__").descending(),
         ]
       )
@@ -2903,36 +2905,37 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
     TestHelper.compare(snapshot: snapshot, expected: expectedResults, enforceOrder: false)
   }
 
-  func testSupportsRand() async throws {
-    let collRef = collectionRef(withDocuments: bookDocs)
-    let db = collRef.firestore
-
-    let pipeline = db.pipeline()
-      .collection(collRef.path)
-      .limit(10)
-      .select([RandomExpression().as("result")])
-
-    let snapshot = try await pipeline.execute()
-
-    XCTAssertEqual(snapshot.results.count, 10, "Should fetch 10 documents")
-
-    for doc in snapshot.results {
-      guard let resultValue = doc.get("result") else {
-        XCTFail("Document \(doc.id ?? "unknown") should have a 'result' field")
-        continue
-      }
-      guard let doubleValue = resultValue as? Double else {
-        XCTFail("Result value for document \(doc.id ?? "unknown") is not a Double: \(resultValue)")
-        continue
-      }
-      XCTAssertGreaterThanOrEqual(
-        doubleValue,
-        0.0,
-        "Result for \(doc.id ?? "unknown") should be >= 0.0"
-      )
-      XCTAssertLessThan(doubleValue, 1.0, "Result for \(doc.id ?? "unknown") should be < 1.0")
-    }
-  }
+//  func testSupportsRand() async throws {
+//    let collRef = collectionRef(withDocuments: bookDocs)
+//    let db = collRef.firestore
+//
+//    let pipeline = db.pipeline()
+//      .collection(collRef.path)
+//      .limit(10)
+//      .select([RandomExpression().as("result")])
+//
+//    let snapshot = try await pipeline.execute()
+//
+//    XCTAssertEqual(snapshot.results.count, 10, "Should fetch 10 documents")
+//
+//    for doc in snapshot.results {
+//      guard let resultValue = doc.get("result") else {
+//        XCTFail("Document \(doc.id ?? "unknown") should have a 'result' field")
+//        continue
+//      }
+//      guard let doubleValue = resultValue as? Double else {
+//        XCTFail("Result value for document \(doc.id ?? "unknown") is not a Double:
+//        \(resultValue)")
+//        continue
+//      }
+//      XCTAssertGreaterThanOrEqual(
+//        doubleValue,
+//        0.0,
+//        "Result for \(doc.id ?? "unknown") should be >= 0.0"
+//      )
+//      XCTAssertLessThan(doubleValue, 1.0, "Result for \(doc.id ?? "unknown") should be < 1.0")
+//    }
+//  }
 
   func testSupportsArray() async throws {
     let db = firestore()
@@ -3104,6 +3107,142 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
     }
   }
 
+  func testMapSetAddsNewField() async throws {
+    let collRef = collectionRef(withDocuments: bookDocs)
+    let db = collRef.firestore
+
+    let pipeline = db.pipeline()
+      .collection(collRef.path)
+      .where(Field("title").equal("The Hitchhiker's Guide to the Galaxy"))
+      .select([
+        Field("awards").mapSet(key: "newAward", value: true).as("modifiedAwards"),
+        Field("title"),
+      ])
+
+    let snapshot = try await pipeline.execute()
+
+    XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document")
+    if let resultDoc = snapshot.results.first {
+      let expectedAwards: [String: Sendable?] = [
+        "hugo": true,
+        "nebula": false,
+        "others": ["unknown": ["year": 1980]],
+        "newAward": true,
+      ]
+      let expectedResult: [String: Sendable?] = [
+        "title": "The Hitchhiker's Guide to the Galaxy",
+        "modifiedAwards": expectedAwards,
+      ]
+      TestHelper.compare(pipelineResult: resultDoc, expected: expectedResult)
+    } else {
+      XCTFail("No document retrieved for testMapSetAddsNewField")
+    }
+  }
+
+  func testMapSetUpdatesExistingField() async throws {
+    let collRef = collectionRef(withDocuments: bookDocs)
+    let db = collRef.firestore
+
+    let pipeline = db.pipeline()
+      .collection(collRef.path)
+      .where(Field("title").equal("The Hitchhiker's Guide to the Galaxy"))
+      .select([
+        Field("awards").mapSet(key: "hugo", value: false).as("modifiedAwards"),
+        Field("title"),
+      ])
+
+    let snapshot = try await pipeline.execute()
+
+    XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document")
+    if let resultDoc = snapshot.results.first {
+      let expectedAwards: [String: Sendable?] = [
+        "hugo": false,
+        "nebula": false,
+        "others": ["unknown": ["year": 1980]],
+      ]
+      let expectedResult: [String: Sendable?] = [
+        "title": "The Hitchhiker's Guide to the Galaxy",
+        "modifiedAwards": expectedAwards,
+      ]
+      TestHelper.compare(pipelineResult: resultDoc, expected: expectedResult)
+    } else {
+      XCTFail("No document retrieved for testMapSetUpdatesExistingField")
+    }
+  }
+
+  func testMapSetWithExpressionValue() async throws {
+    let collRef = collectionRef(withDocuments: bookDocs)
+    let db = collRef.firestore
+
+    let pipeline = db.pipeline()
+      .collection(collRef.path)
+      .where(Field("title").equal("The Hitchhiker's Guide to the Galaxy"))
+      .select(
+        [
+          Field("awards")
+            .mapSet(
+              key: "ratingCategory",
+              value: Field("rating").greaterThan(4.0).then(Constant("high"), else: Constant("low"))
+            )
+            .as("modifiedAwards"),
+          Field("title"),
+        ]
+      )
+
+    let snapshot = try await pipeline.execute()
+
+    XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document")
+    if let resultDoc = snapshot.results.first {
+      let expectedAwards: [String: Sendable?] = [
+        "hugo": true,
+        "nebula": false,
+        "others": ["unknown": ["year": 1980]],
+        "ratingCategory": "high",
+      ]
+      let expectedResult: [String: Sendable?] = [
+        "title": "The Hitchhiker's Guide to the Galaxy",
+        "modifiedAwards": expectedAwards,
+      ]
+      TestHelper.compare(pipelineResult: resultDoc, expected: expectedResult)
+    } else {
+      XCTFail("No document retrieved for testMapSetWithExpressionValue")
+    }
+  }
+
+  func testMapSetWithExpressionKey() async throws {
+    let collRef = collectionRef(withDocuments: bookDocs)
+    let db = collRef.firestore
+
+    let pipeline = db.pipeline()
+      .collection(collRef.path)
+      .where(Field("title").equal("The Hitchhiker's Guide to the Galaxy"))
+      .select([
+        Field("awards")
+          .mapSet(key: Constant("dynamicKey"), value: "dynamicValue")
+          .as("modifiedAwards"),
+        Field("title"),
+      ])
+
+    let snapshot = try await pipeline.execute()
+
+    XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document")
+    if let resultDoc = snapshot.results.first {
+      let expectedAwards: [String: Sendable?] = [
+        "hugo": true,
+        "nebula": false,
+        "others": ["unknown": ["year": 1980]],
+        "dynamicKey": "dynamicValue",
+      ]
+      let expectedResult: [String: Sendable?] = [
+        "title": "The Hitchhiker's Guide to the Galaxy",
+        "modifiedAwards": expectedAwards,
+      ]
+      TestHelper.compare(pipelineResult: resultDoc, expected: expectedResult)
+    } else {
+      XCTFail("No document retrieved for testMapSetWithExpressionKey")
+    }
+  }
+
   func testSupportsTimestampConversions() async throws {
     let db = firestore()
     let randomCol = collectionRef() // Unique collection for this test
@@ -3172,12 +3311,16 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
           Field("timestamp").timestampAdd(10, .second).as("plus10seconds"),
           Field("timestamp").timestampAdd(10, .microsecond).as("plus10micros"),
           Field("timestamp").timestampAdd(10, .millisecond).as("plus10millis"),
+          Field("timestamp").timestampAdd(amount: Constant(10), unit: "day")
+            .as("plus10daysExprUnitSendable"),
           Field("timestamp").timestampSubtract(10, .day).as("minus10days"),
           Field("timestamp").timestampSubtract(10, .hour).as("minus10hours"),
           Field("timestamp").timestampSubtract(10, .minute).as("minus10minutes"),
           Field("timestamp").timestampSubtract(10, .second).as("minus10seconds"),
           Field("timestamp").timestampSubtract(10, .microsecond).as("minus10micros"),
           Field("timestamp").timestampSubtract(10, .millisecond).as("minus10millis"),
+          Field("timestamp").timestampSubtract(amount: Constant(10), unit: "day")
+            .as("minus10daysExprUnitSendable"),
         ]
       )
 
@@ -3190,12 +3333,14 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
       "plus10seconds": Timestamp(seconds: 1_741_380_245, nanoseconds: 0),
       "plus10micros": Timestamp(seconds: 1_741_380_235, nanoseconds: 10000),
       "plus10millis": Timestamp(seconds: 1_741_380_235, nanoseconds: 10_000_000),
+      "plus10daysExprUnitSendable": Timestamp(seconds: 1_742_244_235, nanoseconds: 0),
       "minus10days": Timestamp(seconds: 1_740_516_235, nanoseconds: 0),
       "minus10hours": Timestamp(seconds: 1_741_344_235, nanoseconds: 0),
       "minus10minutes": Timestamp(seconds: 1_741_379_635, nanoseconds: 0),
       "minus10seconds": Timestamp(seconds: 1_741_380_225, nanoseconds: 0),
       "minus10micros": Timestamp(seconds: 1_741_380_234, nanoseconds: 999_990_000),
       "minus10millis": Timestamp(seconds: 1_741_380_234, nanoseconds: 990_000_000),
+      "minus10daysExprUnitSendable": Timestamp(seconds: 1_740_516_235, nanoseconds: 0),
     ]
 
     XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document")
@@ -3206,6 +3351,56 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
     }
   }
 
+  func testTimestampTruncWorks() async throws {
+    let db = firestore()
+    let randomCol = collectionRef()
+    try await randomCol.document("dummyDoc").setData(["field": "value"])
+
+    let baseTimestamp = Timestamp(seconds: 1_741_380_235, nanoseconds: 123_456_000)
+
+    let pipeline = db.pipeline()
+      .collection(randomCol.path)
+      .limit(1)
+      .select(
+        [
+          Constant(baseTimestamp).timestampTruncate(granularity: "nanosecond").as("truncNano"),
+          Constant(baseTimestamp).timestampTruncate(granularity: .microsecond).as("truncMicro"),
+          Constant(baseTimestamp).timestampTruncate(granularity: .millisecond).as("truncMilli"),
+          Constant(baseTimestamp).timestampTruncate(granularity: .second).as("truncSecond"),
+          Constant(baseTimestamp).timestampTruncate(granularity: .minute).as("truncMinute"),
+          Constant(baseTimestamp).timestampTruncate(granularity: .hour).as("truncHour"),
+          Constant(baseTimestamp).timestampTruncate(granularity: .day).as("truncDay"),
+          Constant(baseTimestamp).timestampTruncate(granularity: "month").as("truncMonth"),
+          Constant(baseTimestamp).timestampTruncate(granularity: "year").as("truncYear"),
+          Constant(baseTimestamp).timestampTruncate(granularity: Constant("day"))
+            .as("truncDayExpr"),
+        ]
+      )
+
+    let snapshot = try await pipeline.execute()
+
+    XCTAssertEqual(snapshot.results.count, 1, "Should retrieve one document")
+
+    let expectedResults: [String: Timestamp] = [
+      "truncNano": Timestamp(seconds: 1_741_380_235, nanoseconds: 123_456_000),
+      "truncMicro": Timestamp(seconds: 1_741_380_235, nanoseconds: 123_456_000),
+      "truncMilli": Timestamp(seconds: 1_741_380_235, nanoseconds: 123_000_000),
+      "truncSecond": Timestamp(seconds: 1_741_380_235, nanoseconds: 0),
+      "truncMinute": Timestamp(seconds: 1_741_380_180, nanoseconds: 0),
+      "truncHour": Timestamp(seconds: 1_741_377_600, nanoseconds: 0),
+      "truncDay": Timestamp(seconds: 1_741_305_600, nanoseconds: 0), // Assuming UTC day start
+      "truncMonth": Timestamp(seconds: 1_740_787_200, nanoseconds: 0), // Assuming UTC month start
+      "truncYear": Timestamp(seconds: 1_735_689_600, nanoseconds: 0), // Assuming UTC year start
+      "truncDayExpr": Timestamp(seconds: 1_741_305_600, nanoseconds: 0), // Assuming UTC day start
+    ]
+
+    if let resultDoc = snapshot.results.first {
+      TestHelper.compare(pipelineResult: resultDoc, expected: expectedResults)
+    } else {
+      XCTFail("No document retrieved for timestamp trunc test")
+    }
+  }
+
   func testCurrentTimestampWorks() async throws {
     let collRef = collectionRef(withDocuments: ["doc1": ["foo": 1]])
     let db = collRef.firestore
@@ -3308,144 +3503,6 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
     }
   }
 
-//  func testReplaceFirst() async throws {
-//    try XCTSkipIf(true, "Skip this test since backend has not yet supported.")
-//    let collRef = collectionRef(withDocuments: bookDocs)
-//    let db = collRef.firestore
-//
-//    let pipeline = db.pipeline()
-//      .collection(collRef.path)
-//      .where(Field("title").equal("The Lord of the Rings"))
-//      .limit(1)
-//      .select([Field("title").replaceFirst("o", with: "0").as("newName")])
-//    let snapshot = try await pipeline.execute()
-//    TestHelper.compare(
-//      snapshot: snapshot,
-//      expected: [["newName": "The L0rd of the Rings"]],
-//      enforceOrder: false
-//    )
-//  }
-
-//  func testStringReplace() async throws {
-//    try XCTSkipIf(true, "Skip this test since backend has not yet supported.")
-//    let collRef = collectionRef(withDocuments: bookDocs)
-//    let db = collRef.firestore
-//
-//    let pipeline = db.pipeline()
-//      .collection(collRef.path)
-//      .where(Field("title").equal("The Lord of the Rings"))
-//      .limit(1)
-//      .select([Field("title").stringReplace("o", with: "0").as("newName")])
-//    let snapshot = try await pipeline.execute()
-//    TestHelper.compare(
-//      snapshot: snapshot,
-//      expected: [["newName": "The L0rd 0f the Rings"]],
-//      enforceOrder: false
-//    )
-//  }
-
-//  func testBitAnd() async throws {
-//    try XCTSkipIf(true, "Skip this test since backend has not yet supported.")
-//    let db = firestore()
-//    let randomCol = collectionRef()
-//    try await randomCol.document("dummyDoc").setData(["field": "value"])
-//
-//    let pipeline = db.pipeline()
-//      .collection(randomCol.path)
-//      .limit(1)
-//      .select([Constant(5).bitAnd(12).as("result")])
-//    let snapshot = try await pipeline.execute()
-//    TestHelper.compare(snapshot: snapshot, expected: [["result": 4]], enforceOrder: false)
-//  }
-//
-//  func testBitOr() async throws {
-//    try XCTSkipIf(true, "Skip this test since backend has not yet supported.")
-//    let db = firestore()
-//    let randomCol = collectionRef()
-//    try await randomCol.document("dummyDoc").setData(["field": "value"])
-//
-//    let pipeline = db.pipeline()
-//      .collection(randomCol.path)
-//      .limit(1)
-//      .select([Constant(5).bitOr(12).as("result")])
-//    let snapshot = try await pipeline.execute()
-//    TestHelper.compare(snapshot: snapshot, expected: [["result": 13]], enforceOrder: false)
-//  }
-//
-//  func testBitXor() async throws {
-//    try XCTSkipIf(true, "Skip this test since backend has not yet supported.")
-//    let db = firestore()
-//    let randomCol = collectionRef()
-//    try await randomCol.document("dummyDoc").setData(["field": "value"])
-//
-//    let pipeline = db.pipeline()
-//      .collection(randomCol.path)
-//      .limit(1)
-//      .select([Constant(5).bitXor(12).as("result")])
-//    let snapshot = try await pipeline.execute()
-//    TestHelper.compare(snapshot: snapshot, expected: [["result": 9]], enforceOrder: false)
-//  }
-//
-//  func testBitNot() async throws {
-//    try XCTSkipIf(true, "Skip this test since backend has not yet supported.")
-//    let db = firestore()
-//    let randomCol = collectionRef()
-//    try await randomCol.document("dummyDoc").setData(["field": "value"])
-//    let bytesInput = Data([0xFD])
-//    let expectedOutput = Data([0x02])
-//
-//    let pipeline = db.pipeline()
-//      .collection(randomCol.path)
-//      .limit(1)
-//      .select([Constant(bytesInput).bitNot().as("result")])
-//    let snapshot = try await pipeline.execute()
-//    TestHelper.compare(
-//      snapshot: snapshot,
-//      expected: [["result": expectedOutput]],
-//      enforceOrder: false
-//    )
-//  }
-//
-//  func testBitLeftShift() async throws {
-//    try XCTSkipIf(true, "Skip this test since backend has not yet supported.")
-//    let db = firestore()
-//    let randomCol = collectionRef()
-//    try await randomCol.document("dummyDoc").setData(["field": "value"])
-//    let bytesInput = Data([0x02])
-//    let expectedOutput = Data([0x08])
-//
-//    let pipeline = db.pipeline()
-//      .collection(randomCol.path)
-//      .limit(1)
-//      .select([Constant(bytesInput).bitLeftShift(2).as("result")])
-//    let snapshot = try await pipeline.execute()
-//    TestHelper.compare(
-//      snapshot: snapshot,
-//      expected: [["result": expectedOutput]],
-//      enforceOrder: false
-//    )
-//  }
-//
-//  func testBitRightShift() async throws {
-//    try XCTSkipIf(true, "Skip this test since backend has not yet supported.")
-//    let db = firestore()
-//    let randomCol = collectionRef()
-//    try await randomCol.document("dummyDoc").setData(["field": "value"])
-//    let bytesInput = Data([0x02])
-//    let expectedOutput = Data([0x00])
-//
-//    let pipeline = db.pipeline()
-//      .collection(randomCol.path)
-//      .limit(1)
-//      .select([Constant(bytesInput).bitRightShift(2).as("result")])
-//    let snapshot = try await pipeline.execute()
-//    TestHelper.compare(
-//      snapshot: snapshot,
-//      expected: [["result": expectedOutput]],
-//      enforceOrder: false
-//    )
-//  }
-
   func testDocumentId() async throws {
     try XCTSkipIf(true, "Skip this test since backend has not yet supported.")
     let collRef = collectionRef(withDocuments: bookDocs)
@@ -3585,22 +3642,39 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
     )
   }
 
-  func testTrim() async throws {
-    try XCTSkipIf(true, "Skip this test since backend has not yet supported.")
+  func testTrimCharactersWithStringLiteral() async throws {
+    let collRef = collectionRef(withDocuments: bookDocs)
+    let db = collRef.firestore
+
+    let pipeline = db.pipeline()
+      .collection(collRef.path)
+      .addFields([Constant("---Hello World---").as("paddedString")])
+      .select([Field("paddedString").trim("-").as("trimmedString")])
+      .limit(1)
+    let snapshot = try await pipeline.execute()
+    TestHelper.compare(
+      snapshot: snapshot,
+      expected: [[
+        "trimmedString": "Hello World",
+      ]],
+      enforceOrder: false
+    )
+  }
+
+  func testTrimCharactersWithExpression() async throws {
     let collRef = collectionRef(withDocuments: bookDocs)
     let db = collRef.firestore
 
     let pipeline = db.pipeline()
       .collection(collRef.path)
-      .addFields([Constant(" The Hitchhiker's Guide to the Galaxy ").as("spacedTitle")])
-      .select([Field("spacedTitle").trim().as("trimmedTitle"), Field("spacedTitle")])
+      .addFields([Constant("---Hello World---").as("paddedString"), Constant("-").as("trimChar")])
+      .select([Field("paddedString").trim(Field("trimChar")).as("trimmedString")])
       .limit(1)
     let snapshot = try await pipeline.execute()
     TestHelper.compare(
       snapshot: snapshot,
       expected: [[
-        "spacedTitle": " The Hitchhiker's Guide to the Galaxy ",
-        "trimmedTitle": "The Hitchhiker's Guide to the Galaxy",
+        "trimmedString": "Hello World",
       ]],
       enforceOrder: false
     )