diff --git a/Firestore/Swift/Source/ExpressionImplementation.swift b/Firestore/Swift/Source/ExpressionImplementation.swift index 112b23a9710..363b4cfb5c7 100644 --- a/Firestore/Swift/Source/ExpressionImplementation.swift +++ b/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,7 @@ 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 +142,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 +159,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 +174,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 +191,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 +209,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 +226,7 @@ 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 +241,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 +258,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 +272,7 @@ 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 +287,7 @@ 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 +304,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 +323,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 +340,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,7 +359,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]) + return FunctionExpression(functionName: "string_replace", args: [self, find, replace]) } // MARK: Equivalence Operations @@ -352,7 +370,7 @@ extension Expression { /// - 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 BooleanExpression(functionName: "equivalent", args: [self, Helper.sendableToExpr(other)]) } } @@ -364,215 +382,215 @@ 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,166 +598,166 @@ 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]) + return FunctionExpression(functionName: "trim", args: [self]) } 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) } // --- Added Aggregate Operations (on Expr) --- @@ -771,131 +789,131 @@ public extension Expression { // 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]) + return FunctionExpression(functionName: "timestamp_add", args: [self, unit, amount]) } 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]) + return FunctionExpression(functionName: "timestamp_subtract", args: [self, 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 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 +928,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) } } diff --git a/Firestore/Swift/Source/Helper/PipelineHelper.swift b/Firestore/Swift/Source/Helper/PipelineHelper.swift index b5b38e8dbfe..197a5c530cb 100644 --- a/Firestore/Swift/Source/Helper/PipelineHelper.swift +++ b/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. diff --git a/Firestore/Swift/Source/SwiftAPI/Stages.swift b/Firestore/Swift/Source/Stages.swift similarity index 100% rename from Firestore/Swift/Source/SwiftAPI/Stages.swift rename to Firestore/Swift/Source/Stages.swift diff --git a/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift b/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift index d270c316f62..4c85988304e 100644 --- a/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift +++ b/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift @@ -22,6 +22,30 @@ import Foundation @objc public extension Firestore { + /// Creates a `PipelineSource` that can be used to build and execute a pipeline of operations on the Firestore database. + /// + /// A pipeline is a sequence of stages that are executed in order. Each stage can perform an operation on the data, such as filtering, sorting, or transforming it. + /// + /// Example usage: + /// ```swift + /// let db = Firestore.firestore() + /// let pipeline = db.pipeline() + /// .collection("books") + /// .where(Field("rating").isGreaterThan(4.5)) + /// .sort([Field("rating").descending()]) + /// .limit(2) + /// + /// do { + /// let snapshot = try await pipeline.execute() + /// for doc in snapshot.results { + /// print(doc.data()) + /// } + /// } catch { + /// print("Error executing pipeline: \(error)") + /// } + /// ``` + /// + /// - Returns: A `PipelineSource` that can be used to build and execute a pipeline. @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 +53,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 diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/AggregateFunction.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/AggregateFunction.swift index 3adf83239db..d4e224b7028 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/AggregateFunction.swift +++ b/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) } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/AliasedAggregate.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/AliasedAggregate.swift index 5c16126c6a8..4b93953dc84 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/AliasedAggregate.swift +++ b/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 } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/CountAll.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/CountAll.swift index 2c08f8e31d0..2fad4903d0d 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Aggregates/CountAll.swift +++ b/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: []) } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/DistanceMeasure.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/DistanceMeasure.swift index a4946946485..39e6cdd3321 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/DistanceMeasure.swift +++ b/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) { diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/AliasedExpression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/AliasedExpression.swift index 0468edd4a44..f19232d7f07 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/AliasedExpression.swift +++ b/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 diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Expression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Expression.swift index 8e483a85c7a..6f381292c56 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Expression.swift +++ b/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,97 @@ 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 `where` clauses. 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 `where` clauses. 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 `where` clauses. 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 `where` clauses. 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 `where` clauses. 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 `where` clauses. 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 `where` clauses. 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 `where` clauses. 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 `where` clauses. 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 `where` clauses. 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 `where` clauses. 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 `where` clauses. 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 +553,11 @@ 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 `where` clauses. 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 +565,11 @@ 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 `where` clauses. 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 +577,11 @@ 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 `where` clauses. 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 +589,11 @@ 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 `where` clauses. 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 +601,11 @@ 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 `where` clauses. 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 +613,17 @@ 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 `where` clauses. 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 +633,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 +674,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 +734,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 +747,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 +761,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 +774,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 +788,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 +801,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 +815,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 +829,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 +883,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. @@ -965,7 +946,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 +954,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 +965,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 +979,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 + /// - 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 `FunctionExpr` representing the substring. + /// - Returns: A new `FunctionExpression` representing the substring. func substring(position: Expression, length: Expression?) -> FunctionExpression // MARK: Map Operations @@ -1053,45 +1030,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 + /// - Parameter keyExpression: An `Expression` (evaluating to a string) representing the 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(_ 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 +1070,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,15 +1078,13 @@ 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 // MARK: Aggregations @@ -1187,8 +1156,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. /// @@ -1465,8 +1432,7 @@ public protocol Expression: Sendable { 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. + /// 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. /// @@ -1483,8 +1449,7 @@ public protocol Expression: Sendable { func timestampSubtract(amount: Expression, unit: Expression) -> 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 @@ -1499,8 +1464,6 @@ public protocol Expression: Sendable { /// Creates an expression that returns the document ID from a path. /// - /// - Note: This API is in beta. - /// /// ```swift /// // Get the document ID from a path. /// Field(FieldPath.documentID()).documentId() @@ -1514,26 +1477,20 @@ 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 +1505,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") diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Field.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Field.swift index a2b0c74fc77..45607ec3f7a 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Field.swift +++ b/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 diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ArrayExpression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ArrayExpression.swift index 25fc28b3d89..e5c8e4426b4 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ArrayExpression.swift +++ b/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) } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/BooleanExpression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/BooleanExpression.swift index c29703bf881..d5c77120b14 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/BooleanExpression.swift +++ b/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 @@ -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]) } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ConditionalExpression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ConditionalExpression.swift index 93638f5d916..fb5b01a0237 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ConditionalExpression.swift +++ b/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]) } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/CurrentTimestamp.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/CurrentTimestamp.swift index 914394a4147..5ce275c2f61 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/CurrentTimestamp.swift +++ b/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: []) } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ErrorExpression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ErrorExpression.swift index 7e045ffbf50..8926905677a 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/ErrorExpression.swift +++ b/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)]) } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/FunctionExpression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/FunctionExpression.swift index 825487c9a56..3d7a88e6000 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/FunctionExpression.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/FunctionExpression.swift @@ -12,18 +12,28 @@ // 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() } ) } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/MapExpression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/MapExpression.swift index f7bd9628bc0..8501c28f9ee 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/MapExpression.swift +++ b/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) } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/RandomExpression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/RandomExpression.swift index 9a4ff22a958..7c272b70c99 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/RandomExpression.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/RandomExpression.swift @@ -29,6 +29,6 @@ public class RandomExpression: FunctionExpression, @unchecked Sendable { /// Creates a new `RandomExpression` that generates a random number. public init() { - super.init("rand", []) + super.init(functionName: "rand", args: []) } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Ordering.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Ordering.swift index f9090e8dd41..f4240685cc1 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Ordering.swift +++ b/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) { diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift index 593d16fb669..9f7544bde3e 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Pipeline.swift +++ b/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 +/// 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 = ... diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift index 5c58feb9c7c..bc78b8128e3 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/PipelineSource.swift @@ -12,6 +12,7 @@ // 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 +23,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 +50,36 @@ 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 diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipeline.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipeline.swift index 3883eeb70e6..2110974f7be 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipeline.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipeline.swift @@ -69,31 +69,16 @@ struct PipelineListenOptions: Sendable, Equatable, Hashable { self.includeMetadataChanges = includeMetadataChanges self.source = source bridge = __PipelineListenOptionsBridge( - serverTimestampBehavior: PipelineListenOptions - .toRawValue(servertimestamp: self.serverTimestamps ?? .none), + serverTimestampBehavior: (self.serverTimestamps ?? .none).rawValue, includeMetadata: self.includeMetadataChanges ?? false, source: self.source ?? ListenSource.default ) } - - private static func toRawValue(servertimestamp: ServerTimestampBehavior) -> String { - switch servertimestamp { - case .none: - return "none" - case .estimate: - return "estimate" - case .previous: - return "previous" - default: - fatalError("Unknown server timestamp behavior") - } - } } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) struct RealtimePipeline: @unchecked Sendable { private var stages: [Stage] - let bridge: RealtimePipelineBridge let db: Firestore diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Selectable.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Selectable.swift index a9c655f4e6a..825d9cc42ef 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Selectable.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Selectable.swift @@ -12,4 +12,11 @@ // 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 {} diff --git a/Firestore/Swift/Tests/Integration/PipelineApiTests.swift b/Firestore/Swift/Tests/Integration/PipelineApiTests.swift index fb6f8193d56..20096529f97 100644 --- a/Firestore/Swift/Tests/Integration/PipelineApiTests.swift +++ b/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")]) } } diff --git a/Firestore/Swift/Tests/Integration/PipelineTests.swift b/Firestore/Swift/Tests/Integration/PipelineTests.swift index 9a201cd7866..97f348ac8b8 100644 --- a/Firestore/Swift/Tests/Integration/PipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/PipelineTests.swift @@ -2758,7 +2758,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,7 +2786,7 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { let pipeline = db.pipeline() .collection(collRef.path) .where( - BooleanExpression("and", [Field("rating").greaterThan(0), + BooleanExpression(functionName: "and", args: [Field("rating").greaterThan(0), Field("title").charLength().lessThan(5), Field("tags").arrayContains("propaganda")]) ) @@ -2810,8 +2810,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")]) @@ -2858,7 +2858,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(), ] )