diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index c841ac58da0..5a1dd41c53a 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -823,6 +823,9 @@ 621D620B28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621D620928F9CE7400D2FA26 /* QueryIntegrationTests.swift */; }; 621D620C28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 621D620928F9CE7400D2FA26 /* QueryIntegrationTests.swift */; }; 623AA12C3481646B0715006D /* string_apple_test.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0EE5300F8233D14025EF0456 /* string_apple_test.mm */; }; + 6271643C2ED4D5F400D2CD1D /* RealtimePipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6271643B2ED4D5EE00D2CD1D /* RealtimePipelineTests.swift */; }; + 6271643D2ED4D5F400D2CD1D /* RealtimePipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6271643B2ED4D5EE00D2CD1D /* RealtimePipelineTests.swift */; }; + 6271643E2ED4D5F400D2CD1D /* RealtimePipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6271643B2ED4D5EE00D2CD1D /* RealtimePipelineTests.swift */; }; 627253FDEC6BB5549FE77F4E /* tree_sorted_map_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 549CCA4D20A36DBB00BCEB75 /* tree_sorted_map_test.cc */; }; 62B1C1100A8C68D94565916C /* document_overlay_cache_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = FFCA39825D9678A03D1845D0 /* document_overlay_cache_test.cc */; }; 62C86789E72E624A27BF6AE5 /* complex_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = B32C2DDDEC16F6465317B8AE /* complex_test.cc */; }; @@ -2143,6 +2146,7 @@ 61F72C5520BC48FD001A68CB /* serializer_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = serializer_test.cc; sourceTree = ""; }; 620C1427763BA5D3CCFB5A1F /* BridgingHeader.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = BridgingHeader.h; sourceTree = ""; }; 621D620928F9CE7400D2FA26 /* QueryIntegrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryIntegrationTests.swift; sourceTree = ""; }; + 6271643B2ED4D5EE00D2CD1D /* RealtimePipelineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealtimePipelineTests.swift; sourceTree = ""; }; 62CF8E2E7611B285B46228FE /* Pods-Firestore_IntegrationTests_iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_IntegrationTests_iOS.release.xcconfig"; path = "Target Support Files/Pods-Firestore_IntegrationTests_iOS/Pods-Firestore_IntegrationTests_iOS.release.xcconfig"; sourceTree = ""; }; 62E54B832A9E910A003347C8 /* IndexingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndexingTests.swift; sourceTree = ""; }; 63136A2371C0C013EC7A540C /* target_index_matcher_test.cc */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.cpp.cpp; path = target_index_matcher_test.cc; sourceTree = ""; }; @@ -2499,6 +2503,7 @@ 861684E49DAC993D153E60D0 /* PipelineTests.swift */, 621D620928F9CE7400D2FA26 /* QueryIntegrationTests.swift */, 128F2B002E254E2C0006327E /* QueryToPipelineTests.swift */, + 6271643B2ED4D5EE00D2CD1D /* RealtimePipelineTests.swift */, 4D65F6E69993611D47DC8E7C /* SnapshotListenerSourceTests.swift */, EFF22EA92C5060A4009A369B /* VectorIntegrationTests.swift */, ); @@ -4978,6 +4983,7 @@ 655F8647F57E5F2155DFF7B5 /* PipelineTests.swift in Sources */, 621D620C28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */, 128F2B022E254E2C0006327E /* QueryToPipelineTests.swift in Sources */, + 6271643E2ED4D5F400D2CD1D /* RealtimePipelineTests.swift in Sources */, 1CFBD4563960D8A20C4679A3 /* SnapshotListenerSourceTests.swift in Sources */, EE4C4BE7F93366AE6368EE02 /* TestHelper.swift in Sources */, EFF22EAC2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */, @@ -5012,8 +5018,8 @@ E3E6B368A755D892F937DBF7 /* collection_group_test.cc in Sources */, 064689971747DA312770AB7A /* collection_test.cc in Sources */, 1DB3013C5FC736B519CD65A3 /* common.pb.cc in Sources */, - 99F97B28DA546D42AB14214B /* comparison_test.cc in Sources */, 555161D6DB2DDC8B57F72A70 /* comparison_test.cc in Sources */, + 99F97B28DA546D42AB14214B /* comparison_test.cc in Sources */, BB5F19878EA5A8D9C7276D40 /* complex_test.cc in Sources */, 7394B5C29C6E524C2AF964E6 /* counting_query_engine.cc in Sources */, C02A969BF4BB63ABCB531B4B /* create_noop_connectivity_monitor.cc in Sources */, @@ -5259,6 +5265,7 @@ C8C2B945D84DD98391145F3F /* PipelineTests.swift in Sources */, 621D620B28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */, 128F2B032E254E2C0006327E /* QueryToPipelineTests.swift in Sources */, + 6271643C2ED4D5F400D2CD1D /* RealtimePipelineTests.swift in Sources */, A0BC30D482B0ABD1A3A24CDC /* SnapshotListenerSourceTests.swift in Sources */, A78366DBE0BFDE42474A728A /* TestHelper.swift in Sources */, EFF22EAB2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */, @@ -5293,8 +5300,8 @@ 1CDA0E10BC669276E0EAA1E8 /* collection_group_test.cc in Sources */, C87DF880BADEA1CBF8365700 /* collection_test.cc in Sources */, 1D71CA6BBA1E3433F243188E /* common.pb.cc in Sources */, - 476AE05E0878007DE1BF5460 /* comparison_test.cc in Sources */, 9C86EEDEA131BFD50255EEF1 /* comparison_test.cc in Sources */, + 476AE05E0878007DE1BF5460 /* comparison_test.cc in Sources */, C5434EF8A0C8B79A71F0784C /* complex_test.cc in Sources */, DCD83C545D764FB15FD88B02 /* counting_query_engine.cc in Sources */, ECC433628575AE994C621C54 /* create_noop_connectivity_monitor.cc in Sources */, @@ -5822,6 +5829,7 @@ E04CB0D580980748D5DC453F /* PipelineTests.swift in Sources */, 621D620A28F9CE7400D2FA26 /* QueryIntegrationTests.swift in Sources */, 128F2B012E254E2C0006327E /* QueryToPipelineTests.swift in Sources */, + 6271643D2ED4D5F400D2CD1D /* RealtimePipelineTests.swift in Sources */, B00F8D1819EE20C45B660940 /* SnapshotListenerSourceTests.swift in Sources */, AD34726BFD3461FF64BBD56D /* TestHelper.swift in Sources */, EFF22EAA2C5060A4009A369B /* VectorIntegrationTests.swift in Sources */, @@ -5856,8 +5864,8 @@ 4A6B1E0B678E31367A55DC17 /* collection_group_test.cc in Sources */, BACA9CDF0F2E926926B5F36F /* collection_test.cc in Sources */, 4C66806697D7BCA730FA3697 /* common.pb.cc in Sources */, - C885C84B7549C860784E4E3C /* comparison_test.cc in Sources */, EC7A44792A5513FBB6F501EE /* comparison_test.cc in Sources */, + C885C84B7549C860784E4E3C /* comparison_test.cc in Sources */, 62C86789E72E624A27BF6AE5 /* complex_test.cc in Sources */, BDF3A6C121F2773BB3A347A7 /* counting_query_engine.cc in Sources */, 1F4930A8366F74288121F627 /* create_noop_connectivity_monitor.cc in Sources */, diff --git a/Firestore/Swift/Source/ExpressionImplementation.swift b/Firestore/Swift/Source/ExpressionImplementation.swift index 5786f264770..aecfb3c75b1 100644 --- a/Firestore/Swift/Source/ExpressionImplementation.swift +++ b/Firestore/Swift/Source/ExpressionImplementation.swift @@ -376,6 +376,24 @@ extension Expression { } public extension Expression { + func asBoolean() -> BooleanExpression { + switch self { + case let boolExpr as BooleanExpression: + return boolExpr + case let constant as Constant: + return BooleanConstant(constant) + case let field as Field: + return BooleanField(field) + case let funcExpr as FunctionExpression: + return BooleanFunctionExpression(funcExpr) + default: + // This should be unreachable if all expression types are handled. + fatalError( + "Unknown expression type \(Swift.type(of: self)) cannot be converted to BooleanExpression" + ) + } + } + func `as`(_ name: String) -> AliasedExpression { return AliasedExpression(self, name) } @@ -474,38 +492,56 @@ public extension Expression { } func arrayContains(_ element: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "array_contains", args: [self, element]) + return BooleanFunctionExpression(functionName: "array_contains", args: [self, element]) } func arrayContains(_ element: Sendable) -> BooleanExpression { - return BooleanExpression( + return BooleanFunctionExpression( functionName: "array_contains", args: [self, Helper.sendableToExpr(element)] ) } func arrayContainsAll(_ values: [Expression]) -> BooleanExpression { - return BooleanExpression(functionName: "array_contains_all", args: [self, Helper.array(values)]) + return BooleanFunctionExpression( + functionName: "array_contains_all", + args: [self, Helper.array(values)] + ) } func arrayContainsAll(_ values: [Sendable]) -> BooleanExpression { - return BooleanExpression(functionName: "array_contains_all", args: [self, Helper.array(values)]) + return BooleanFunctionExpression( + functionName: "array_contains_all", + args: [self, Helper.array(values)] + ) } func arrayContainsAll(_ arrayExpression: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "array_contains_all", args: [self, arrayExpression]) + return BooleanFunctionExpression( + functionName: "array_contains_all", + args: [self, arrayExpression] + ) } func arrayContainsAny(_ values: [Expression]) -> BooleanExpression { - return BooleanExpression(functionName: "array_contains_any", args: [self, Helper.array(values)]) + return BooleanFunctionExpression( + functionName: "array_contains_any", + args: [self, Helper.array(values)] + ) } func arrayContainsAny(_ values: [Sendable]) -> BooleanExpression { - return BooleanExpression(functionName: "array_contains_any", args: [self, Helper.array(values)]) + return BooleanFunctionExpression( + functionName: "array_contains_any", + args: [self, Helper.array(values)] + ) } func arrayContainsAny(_ arrayExpression: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "array_contains_any", args: [self, arrayExpression]) + return BooleanFunctionExpression( + functionName: "array_contains_any", + args: [self, arrayExpression] + ) } func arrayLength() -> FunctionExpression { @@ -532,80 +568,89 @@ public extension Expression { } func greaterThan(_ other: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "greater_than", args: [self, other]) + return BooleanFunctionExpression(functionName: "greater_than", args: [self, other]) } func greaterThan(_ other: Sendable) -> BooleanExpression { let exprOther = Helper.sendableToExpr(other) - return BooleanExpression(functionName: "greater_than", args: [self, exprOther]) + return BooleanFunctionExpression(functionName: "greater_than", args: [self, exprOther]) } func greaterThanOrEqual(_ other: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "greater_than_or_equal", args: [self, other]) + return BooleanFunctionExpression(functionName: "greater_than_or_equal", args: [self, other]) } func greaterThanOrEqual(_ other: Sendable) -> BooleanExpression { let exprOther = Helper.sendableToExpr(other) - return BooleanExpression(functionName: "greater_than_or_equal", args: [self, exprOther]) + return BooleanFunctionExpression(functionName: "greater_than_or_equal", args: [self, exprOther]) } func lessThan(_ other: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "less_than", args: [self, other]) + return BooleanFunctionExpression(functionName: "less_than", args: [self, other]) } func lessThan(_ other: Sendable) -> BooleanExpression { let exprOther = Helper.sendableToExpr(other) - return BooleanExpression(functionName: "less_than", args: [self, exprOther]) + return BooleanFunctionExpression(functionName: "less_than", args: [self, exprOther]) } func lessThanOrEqual(_ other: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "less_than_or_equal", args: [self, other]) + return BooleanFunctionExpression(functionName: "less_than_or_equal", args: [self, other]) } func lessThanOrEqual(_ other: Sendable) -> BooleanExpression { let exprOther = Helper.sendableToExpr(other) - return BooleanExpression(functionName: "less_than_or_equal", args: [self, exprOther]) + return BooleanFunctionExpression(functionName: "less_than_or_equal", args: [self, exprOther]) } func equal(_ other: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "equal", args: [self, other]) + return BooleanFunctionExpression(functionName: "equal", args: [self, other]) } func equal(_ other: Sendable) -> BooleanExpression { let exprOther = Helper.sendableToExpr(other) - return BooleanExpression(functionName: "equal", args: [self, exprOther]) + return BooleanFunctionExpression(functionName: "equal", args: [self, exprOther]) } func notEqual(_ other: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "not_equal", args: [self, other]) + return BooleanFunctionExpression(functionName: "not_equal", args: [self, other]) } func notEqual(_ other: Sendable) -> BooleanExpression { - return BooleanExpression(functionName: "not_equal", args: [self, Helper.sendableToExpr(other)]) + return BooleanFunctionExpression( + functionName: "not_equal", + args: [self, Helper.sendableToExpr(other)] + ) } func equalAny(_ others: [Expression]) -> BooleanExpression { - return BooleanExpression(functionName: "equal_any", args: [self, Helper.array(others)]) + return BooleanFunctionExpression(functionName: "equal_any", args: [self, Helper.array(others)]) } func equalAny(_ others: [Sendable]) -> BooleanExpression { - return BooleanExpression(functionName: "equal_any", args: [self, Helper.array(others)]) + return BooleanFunctionExpression(functionName: "equal_any", args: [self, Helper.array(others)]) } func equalAny(_ arrayExpression: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "equal_any", args: [self, arrayExpression]) + return BooleanFunctionExpression(functionName: "equal_any", args: [self, arrayExpression]) } func notEqualAny(_ others: [Expression]) -> BooleanExpression { - return BooleanExpression(functionName: "not_equal_any", args: [self, Helper.array(others)]) + return BooleanFunctionExpression( + functionName: "not_equal_any", + args: [self, Helper.array(others)] + ) } func notEqualAny(_ others: [Sendable]) -> BooleanExpression { - return BooleanExpression(functionName: "not_equal_any", args: [self, Helper.array(others)]) + return BooleanFunctionExpression( + functionName: "not_equal_any", + args: [self, Helper.array(others)] + ) } func notEqualAny(_ arrayExpression: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "not_equal_any", args: [self, arrayExpression]) + return BooleanFunctionExpression(functionName: "not_equal_any", args: [self, arrayExpression]) } // MARK: Checks @@ -613,15 +658,15 @@ public extension Expression { // --- Added Type Check Operations --- func exists() -> BooleanExpression { - return BooleanExpression(functionName: "exists", args: [self]) + return BooleanFunctionExpression(functionName: "exists", args: [self]) } func isError() -> BooleanExpression { - return BooleanExpression(functionName: "is_error", args: [self]) + return BooleanFunctionExpression(functionName: "is_error", args: [self]) } func isAbsent() -> BooleanExpression { - return BooleanExpression(functionName: "is_absent", args: [self]) + return BooleanFunctionExpression(functionName: "is_absent", args: [self]) } // --- Added String Operations --- @@ -647,63 +692,69 @@ public extension Expression { } func like(_ pattern: String) -> BooleanExpression { - return BooleanExpression(functionName: "like", args: [self, Helper.sendableToExpr(pattern)]) + return BooleanFunctionExpression( + functionName: "like", + args: [self, Helper.sendableToExpr(pattern)] + ) } func like(_ pattern: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "like", args: [self, pattern]) + return BooleanFunctionExpression(functionName: "like", args: [self, pattern]) } func regexContains(_ pattern: String) -> BooleanExpression { - return BooleanExpression( + return BooleanFunctionExpression( functionName: "regex_contains", args: [self, Helper.sendableToExpr(pattern)] ) } func regexContains(_ pattern: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "regex_contains", args: [self, pattern]) + return BooleanFunctionExpression(functionName: "regex_contains", args: [self, pattern]) } func regexMatch(_ pattern: String) -> BooleanExpression { - return BooleanExpression( + return BooleanFunctionExpression( functionName: "regex_match", args: [self, Helper.sendableToExpr(pattern)] ) } func regexMatch(_ pattern: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "regex_match", args: [self, pattern]) + return BooleanFunctionExpression(functionName: "regex_match", args: [self, pattern]) } func stringContains(_ substring: String) -> BooleanExpression { - return BooleanExpression( + return BooleanFunctionExpression( functionName: "string_contains", args: [self, Helper.sendableToExpr(substring)] ) } func stringContains(_ expression: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "string_contains", args: [self, expression]) + return BooleanFunctionExpression(functionName: "string_contains", args: [self, expression]) } func startsWith(_ prefix: String) -> BooleanExpression { - return BooleanExpression( + return BooleanFunctionExpression( functionName: "starts_with", args: [self, Helper.sendableToExpr(prefix)] ) } func startsWith(_ prefix: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "starts_with", args: [self, prefix]) + return BooleanFunctionExpression(functionName: "starts_with", args: [self, prefix]) } func endsWith(_ suffix: String) -> BooleanExpression { - return BooleanExpression(functionName: "ends_with", args: [self, Helper.sendableToExpr(suffix)]) + return BooleanFunctionExpression( + functionName: "ends_with", + args: [self, Helper.sendableToExpr(suffix)] + ) } func endsWith(_ suffix: Expression) -> BooleanExpression { - return BooleanExpression(functionName: "ends_with", args: [self, suffix]) + return BooleanFunctionExpression(functionName: "ends_with", args: [self, suffix]) } func toLower() -> FunctionExpression { diff --git a/Firestore/Swift/Source/PipelineResultChange.swift b/Firestore/Swift/Source/PipelineResultChange.swift index 253bb828d5e..6c56e47eb45 100644 --- a/Firestore/Swift/Source/PipelineResultChange.swift +++ b/Firestore/Swift/Source/PipelineResultChange.swift @@ -20,7 +20,7 @@ import Foundation @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -struct PipelineResultChange: Sendable { +public struct PipelineResultChange: Sendable { public enum ChangeType { case added, modified, removed } diff --git a/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift b/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift index 27b6df8a3d4..630bedcaafe 100644 --- a/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift +++ b/Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift @@ -60,7 +60,7 @@ import Foundation /// /// - 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 { + @nonobjc func realtimePipeline() -> RealtimePipelineSource { return RealtimePipelineSource(db: self) { stages, db in RealtimePipeline(stages: stages, db: db) } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Expression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Expression.swift index 8b3367b299c..fb2475f3140 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Expression.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/Expression.swift @@ -20,6 +20,11 @@ import Foundation public protocol Expression: Sendable { + /// Casts the expression to a `BooleanExpression`. + /// + /// - Returns: A `BooleanExpression` representing the same expression. + func asBoolean() -> BooleanExpression + /// Assigns an alias to this expression. /// /// Aliases are useful for renaming fields in the output of a stage or for giving meaningful diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/BooleanExpression.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/BooleanExpression.swift index 700d4aa0476..85d436d0e91 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/BooleanExpression.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/Expressions/FunctionExpressions/BooleanExpression.swift @@ -15,7 +15,7 @@ import Foundation /// -/// A `BooleanExpression` is a specialized `FunctionExpression` that evaluates to a boolean value. +/// A `BooleanExpression` is an `Expression` that evaluates to a boolean value. /// /// It is used to construct conditional logic within Firestore pipelines, such as in `where` /// clauses or `ConditionalExpression`. `BooleanExpression` instances can be combined using standard @@ -30,11 +30,126 @@ import Foundation /// (Field("category").equal("electronics") || Field("on_sale").equal(true)) /// ) /// ``` -public class BooleanExpression: FunctionExpression, @unchecked Sendable { - override public init(functionName: String, args: [Expression]) { - super.init(functionName: functionName, args: args) +public protocol BooleanExpression: Expression {} + +struct BooleanFunctionExpression: BooleanExpression, BridgeWrapper { + let expr: FunctionExpression + public var bridge: ExprBridge { return expr.bridge } + + init(_ expr: FunctionExpression) { + self.expr = expr + } + + init(functionName: String, args: [Expression]) { + expr = FunctionExpression(functionName: functionName, args: args) + } +} + +struct BooleanConstant: BooleanExpression, BridgeWrapper { + private let constant: Constant + public var bridge: ExprBridge { return constant.bridge } + + init(_ constant: Constant) { + self.constant = constant + } +} + +struct BooleanField: BooleanExpression, BridgeWrapper { + private let field: Field + public var bridge: ExprBridge { return field.bridge } + + init(_ field: Field) { + self.field = field } +} + +/// Combines two boolean expressions with a logical AND (`&&`). +/// +/// The resulting expression is `true` only if both the left-hand side (`lhs`) and the right-hand +/// side (`rhs`) are `true`. +/// +/// ```swift +/// // Find books in the "Fantasy" genre with a rating greater than 4.5 +/// firestore.pipeline() +/// .collection("books") +/// .where( +/// Field("genre").equal("Fantasy") && Field("rating").greaterThan(4.5) +/// ) +/// ``` +/// +/// - Parameters: +/// - lhs: The left-hand boolean expression. +/// - rhs: The right-hand boolean expression. +/// - Returns: A new `BooleanExpression` representing the logical AND. +public func && (lhs: BooleanExpression, + rhs: @autoclosure () throws -> BooleanExpression) rethrows -> BooleanExpression { + return try BooleanFunctionExpression(functionName: "and", args: [lhs, rhs()]) +} + +/// Combines two boolean expressions with a logical OR (`||`). +/// +/// The resulting expression is `true` if either the left-hand side (`lhs`) or the right-hand +/// side (`rhs`) is `true`. +/// +/// ```swift +/// // Find books that are either in the "Romance" genre or were published before 1900 +/// firestore.pipeline() +/// .collection("books") +/// .where( +/// Field("genre").equal("Romance") || Field("published").lessThan(1900) +/// ) +/// ``` +/// +/// - Parameters: +/// - lhs: The left-hand boolean expression. +/// - rhs: The right-hand boolean expression. +/// - Returns: A new `BooleanExpression` representing the logical OR. +public func || (lhs: BooleanExpression, + rhs: @autoclosure () throws -> BooleanExpression) rethrows -> BooleanExpression { + return try BooleanFunctionExpression(functionName: "or", args: [lhs, rhs()]) +} + +/// Combines two boolean expressions with a logical XOR (`^`). +/// +/// The resulting expression is `true` if the left-hand side (`lhs`) and the right-hand side +/// (`rhs`) have different boolean values. +/// +/// ```swift +/// // Find books that are in the "Dystopian" genre OR have a rating of 5.0, but not both. +/// firestore.pipeline() +/// .collection("books") +/// .where( +/// Field("genre").equal("Dystopian") ^ Field("rating").equal(5.0) +/// ) +/// ``` +/// +/// - Parameters: +/// - lhs: The left-hand boolean expression. +/// - rhs: The right-hand boolean expression. +/// - Returns: A new `BooleanExpression` representing the logical XOR. +public func ^ (lhs: BooleanExpression, + rhs: @autoclosure () throws -> BooleanExpression) rethrows -> BooleanExpression { + return try BooleanFunctionExpression(functionName: "xor", args: [lhs, rhs()]) +} + +/// Negates a boolean expression with a logical NOT (`!`). +/// +/// The resulting expression is `true` if the original expression is `false`, and vice versa. +/// +/// ```swift +/// // Find books that are NOT in the "Science Fiction" genre +/// firestore.pipeline() +/// .collection("books") +/// .where(!Field("genre").equal("Science Fiction")) +/// ``` +/// +/// - Parameter lhs: The boolean expression to negate. +/// - Returns: A new `BooleanExpression` representing the logical NOT. +public prefix func ! (lhs: BooleanExpression) -> BooleanExpression { + return BooleanFunctionExpression(functionName: "not", args: [lhs]) +} +public extension BooleanExpression { /// Creates an aggregation that counts the number of documents for which this boolean expression /// evaluates to `true`. /// @@ -52,7 +167,7 @@ public class BooleanExpression: FunctionExpression, @unchecked Sendable { /// ``` /// /// - Returns: An `AggregateFunction` that performs the conditional count. - public func countIf() -> AggregateFunction { + func countIf() -> AggregateFunction { return AggregateFunction(functionName: "count_if", args: [self]) } @@ -77,100 +192,11 @@ public class BooleanExpression: FunctionExpression, @unchecked Sendable { /// - thenExpression: The `Expression` to evaluate if this boolean expression is `true`. /// - elseExpression: The `Expression` to evaluate if this boolean expression is `false`. /// - Returns: A new `FunctionExpression` representing the conditional logic. - public func then(_ thenExpression: Expression, - else elseExpression: Expression) -> FunctionExpression { + func then(_ thenExpression: Expression, + else elseExpression: Expression) -> FunctionExpression { return FunctionExpression( functionName: "conditional", args: [self, thenExpression, elseExpression] ) } - - /// Combines two boolean expressions with a logical AND (`&&`). - /// - /// The resulting expression is `true` only if both the left-hand side (`lhs`) and the right-hand - /// side (`rhs`) are `true`. - /// - /// ```swift - /// // Find books in the "Fantasy" genre with a rating greater than 4.5 - /// firestore.pipeline() - /// .collection("books") - /// .where( - /// Field("genre").equal("Fantasy") && Field("rating").greaterThan(4.5) - /// ) - /// ``` - /// - /// - Parameters: - /// - lhs: The left-hand boolean expression. - /// - rhs: The right-hand boolean expression. - /// - Returns: A new `BooleanExpression` representing the logical AND. - public static func && (lhs: BooleanExpression, - rhs: @autoclosure () throws -> BooleanExpression) rethrows - -> BooleanExpression { - try BooleanExpression(functionName: "and", args: [lhs, rhs()]) - } - - /// Combines two boolean expressions with a logical OR (`||`). - /// - /// The resulting expression is `true` if either the left-hand side (`lhs`) or the right-hand - /// side (`rhs`) is `true`. - /// - /// ```swift - /// // Find books that are either in the "Romance" genre or were published before 1900 - /// firestore.pipeline() - /// .collection("books") - /// .where( - /// Field("genre").equal("Romance") || Field("published").lessThan(1900) - /// ) - /// ``` - /// - /// - Parameters: - /// - lhs: The left-hand boolean expression. - /// - rhs: The right-hand boolean expression. - /// - Returns: A new `BooleanExpression` representing the logical OR. - public static func || (lhs: BooleanExpression, - rhs: @autoclosure () throws -> BooleanExpression) rethrows - -> BooleanExpression { - try BooleanExpression(functionName: "or", args: [lhs, rhs()]) - } - - /// Combines two boolean expressions with a logical XOR (`^`). - /// - /// The resulting expression is `true` if the left-hand side (`lhs`) and the right-hand side - /// (`rhs`) have different boolean values. - /// - /// ```swift - /// // Find books that are in the "Dystopian" genre OR have a rating of 5.0, but not both. - /// firestore.pipeline() - /// .collection("books") - /// .where( - /// Field("genre").equal("Dystopian") ^ Field("rating").equal(5.0) - /// ) - /// ``` - /// - /// - Parameters: - /// - lhs: The left-hand boolean expression. - /// - rhs: The right-hand boolean expression. - /// - Returns: A new `BooleanExpression` representing the logical XOR. - public static func ^ (lhs: BooleanExpression, - rhs: @autoclosure () throws -> BooleanExpression) rethrows - -> BooleanExpression { - try BooleanExpression(functionName: "xor", args: [lhs, rhs()]) - } - - /// Negates a boolean expression with a logical NOT (`!`). - /// - /// The resulting expression is `true` if the original expression is `false`, and vice versa. - /// - /// ```swift - /// // Find books that are NOT in the "Science Fiction" genre - /// firestore.pipeline() - /// .collection("books") - /// .where(!Field("genre").equal("Science Fiction")) - /// ``` - /// - /// - Parameter lhs: The boolean expression to negate. - /// - Returns: A new `BooleanExpression` representing the logical NOT. - public static prefix func ! (lhs: BooleanExpression) -> BooleanExpression { - return BooleanExpression(functionName: "not", args: [lhs]) - } } diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipeline.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipeline.swift index 3883eeb70e6..12a1919c7ea 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipeline.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipeline.swift @@ -20,10 +20,10 @@ import Foundation @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -struct PipelineListenOptions: Sendable, Equatable, Hashable { +public struct PipelineListenOptions: Sendable, Equatable, Hashable { /// Defines how to handle server-generated timestamps that are not yet known locally /// during latency compensation. - struct ServerTimestampBehavior: Sendable, Equatable, Hashable { + public struct ServerTimestampBehavior: Sendable, Equatable, Hashable { /// The raw string value for the behavior, used for implementation and hashability. let rawValue: String /// Creates a new behavior with a private raw value. @@ -91,7 +91,7 @@ struct PipelineListenOptions: Sendable, Equatable, Hashable { } @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -struct RealtimePipeline: @unchecked Sendable { +public struct RealtimePipeline: @unchecked Sendable { private var stages: [Stage] let bridge: RealtimePipelineBridge @@ -103,7 +103,7 @@ struct RealtimePipeline: @unchecked Sendable { bridge = RealtimePipelineBridge(stages: stages.map { $0.bridge }, db: db) } - struct Snapshot: Sendable { + public struct Snapshot: Sendable { /// An array of all the results in the `PipelineSnapshot`. let results_cache: [PipelineResult] diff --git a/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipelineSource.swift b/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipelineSource.swift index 8928b04f2d1..52e92a1c511 100644 --- a/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipelineSource.swift +++ b/Firestore/Swift/Source/SwiftAPI/Pipeline/RealtimePipelineSource.swift @@ -13,7 +13,7 @@ // limitations under the License. @available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) -struct RealtimePipelineSource: @unchecked Sendable { +public struct RealtimePipelineSource: @unchecked Sendable { let db: Firestore let factory: ([Stage], Firestore) -> RealtimePipeline @@ -22,27 +22,62 @@ struct RealtimePipelineSource: @unchecked Sendable { self.factory = factory } - func collection(_ path: String) -> RealtimePipeline { + public func collection(_ path: String) -> RealtimePipeline { return factory([CollectionSource(collection: db.collection(path), db: db)], db) } - func collection(_ coll: CollectionReference) -> RealtimePipeline { + public func collection(_ coll: CollectionReference) -> RealtimePipeline { return factory([CollectionSource(collection: coll, db: db)], db) } - func collectionGroup(_ collectionId: String) -> RealtimePipeline { + public func collectionGroup(_ collectionId: String) -> RealtimePipeline { return factory( [CollectionGroupSource(collectionId: collectionId)], db ) } - func documents(_ docs: [DocumentReference]) -> RealtimePipeline { + public func documents(_ docs: [DocumentReference]) -> RealtimePipeline { return factory([DocumentsSource(docs: docs, db: db)], db) } - func documents(_ paths: [String]) -> RealtimePipeline { + public func documents(_ paths: [String]) -> RealtimePipeline { let docs = paths.map { db.document($0) } return factory([DocumentsSource(docs: docs, db: db)], db) } + + /// Creates a `RealtimePipeline` 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 `RealtimePipeline` that is equivalent to the given query. + public func create(from query: Query) -> RealtimePipeline { + let stageBridges = PipelineBridge.createStageBridges(from: query) + let stages: [Stage] = stageBridges.map { bridge in + switch bridge.name { + case "collection": + return CollectionSource( + bridge: bridge as! CollectionSourceStageBridge, + db: query.firestore + ) + case "collection_group": + return CollectionGroupSource(bridge: bridge as! CollectionGroupSourceStageBridge) + case "documents": + return DocumentsSource(bridge: bridge as! DocumentsSourceStageBridge, db: query.firestore) + case "where": + return Where(bridge: bridge as! WhereStageBridge) + case "limit": + return Limit(bridge: bridge as! LimitStageBridge) + case "sort": + return Sort(bridge: bridge as! SortStageBridge) + case "offset": + return Offset(bridge: bridge as! OffsetStageBridge) + default: + fatalError("Unknown stage type \(bridge.name)") + } + } + return factory(stages, db) + } } diff --git a/Firestore/Swift/Tests/Integration/PipelineApiTests.swift b/Firestore/Swift/Tests/Integration/PipelineApiTests.swift index 20096529f97..e4434b97830 100644 --- a/Firestore/Swift/Tests/Integration/PipelineApiTests.swift +++ b/Firestore/Swift/Tests/Integration/PipelineApiTests.swift @@ -405,9 +405,6 @@ final class PipelineApiTests: FSTIntegrationTestCase { // This is the same of the logicalMin('price', 0)', if it did not exist _ = FunctionExpression(functionName: "logicalMin", args: [Field("price"), Constant(0)]) - // Create a generic BooleanExpr for use where BooleanExpr is required - _ = BooleanExpression(functionName: "eq", args: [Field("price"), Constant(10)]) - // Create a generic AggregateFunction for use where AggregateFunction is required _ = AggregateFunction(functionName: "sum", args: [Field("price")]) } diff --git a/Firestore/Swift/Tests/Integration/PipelineTests.swift b/Firestore/Swift/Tests/Integration/PipelineTests.swift index 9eb545cb617..050fd173068 100644 --- a/Firestore/Swift/Tests/Integration/PipelineTests.swift +++ b/Firestore/Swift/Tests/Integration/PipelineTests.swift @@ -2783,9 +2783,10 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { let pipeline = db.pipeline() .collection(collRef.path) .where( - BooleanExpression(functionName: "and", args: [Field("rating").greaterThan(0), - Field("title").charLength().lessThan(5), - Field("tags").arrayContains("propaganda")]) + FunctionExpression(functionName: "and", args: [Field("rating").greaterThan(0), + Field("title").charLength().lessThan(5), + Field("tags") + .arrayContains("propaganda")]).asBoolean() ) .select(["title"]) @@ -2806,10 +2807,10 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { let pipeline = db.pipeline() .collection(collRef.path) - .where(BooleanExpression( + .where(FunctionExpression( functionName: "array_contains_any", args: [Field("tags"), ArrayExpression(["politics"])] - )) + ).asBoolean()) .select([Field("title")]) let snapshot = try await pipeline.execute() @@ -3909,4 +3910,35 @@ class PipelineIntegrationTests: FSTIntegrationTestCase { ] TestHelper.compare(snapshot: snapshot, expected: expectedResults, enforceOrder: true) } + + func testFieldAndConstantAsBooleanExpression() async throws { + let collRef = collectionRef(withDocuments: [ + "doc1": ["a": true], + "doc2": ["a": false], + "doc3": ["b": true], + ]) + let db = collRef.firestore + + var pipeline = db.pipeline() + .collection(collRef.path) + .where(Field("a").asBoolean()) + var snapshot = try await pipeline.execute() + TestHelper.compare(snapshot: snapshot, expectedIDs: ["doc1"], enforceOrder: false) + + pipeline = db.pipeline() + .collection(collRef.path) + .where(Constant(true).asBoolean()) + snapshot = try await pipeline.execute() + TestHelper.compare( + snapshot: snapshot, + expectedIDs: ["doc1", "doc2", "doc3"], + enforceOrder: false + ) + + pipeline = db.pipeline() + .collection(collRef.path) + .where(Constant(false).asBoolean()) + snapshot = try await pipeline.execute() + TestHelper.compare(snapshot: snapshot, expectedCount: 0) + } } diff --git a/Firestore/Swift/Tests/Integration/QueryIntegrationTests.swift b/Firestore/Swift/Tests/Integration/QueryIntegrationTests.swift index e5257c7860c..d17c58f14bc 100644 --- a/Firestore/Swift/Tests/Integration/QueryIntegrationTests.swift +++ b/Firestore/Swift/Tests/Integration/QueryIntegrationTests.swift @@ -332,3 +332,41 @@ class QueryIntegrationTests: FSTIntegrationTestCase { ) } } + +class QueryAsPipelineIntegrationTests: QueryIntegrationTests { + override class var isRunningPipeline: Bool { + return true + } + + override func check(_ coll: CollectionReference, query: Query, + matchesResult expectedKeys: [String]) async throws { + let collPipeline = coll.firestore.realtimePipeline().create(from: coll) + var collIterator = collPipeline.snapshotStream().makeAsyncIterator() + var _ = try await collIterator.next() + + let pipeline = query.firestore.realtimePipeline().create(from: query) + + var cacheIterator = pipeline.snapshotStream(options: .init(source: .cache)).makeAsyncIterator() + let cacheSnapshot = try await cacheIterator.next() + let cacheResultIds = cacheSnapshot?.results().map { $0.id } + + var serverIterator = pipeline.snapshotStream(options: .init( + includeMetadataChanges: true, + source: .default + )).makeAsyncIterator() + var serverSnapshot = try await serverIterator.next() + if serverSnapshot?.metadata.isFromCache == true { + serverSnapshot = try await serverIterator.next() + } + let serverResultIds = serverSnapshot?.results().map { $0.id } + + var remoteKeysIterator = pipeline.snapshotStream(options: .init(source: .cache)) + .makeAsyncIterator() + let remoteKeysSnapshot = try await remoteKeysIterator.next() + let remoteKeysResultIds = remoteKeysSnapshot?.results().map { $0.id } + + XCTAssertEqual(cacheResultIds, serverResultIds) + XCTAssertEqual(serverResultIds, remoteKeysResultIds) + XCTAssertEqual(remoteKeysResultIds, expectedKeys) + } +} diff --git a/Firestore/Swift/Tests/Integration/RealtimePipelineTests.swift b/Firestore/Swift/Tests/Integration/RealtimePipelineTests.swift new file mode 100644 index 00000000000..df78858175e --- /dev/null +++ b/Firestore/Swift/Tests/Integration/RealtimePipelineTests.swift @@ -0,0 +1,646 @@ +/* + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import FirebaseFirestore +import Foundation + +private let bookDocs: [String: [String: Any]] = [ + "book1": [ + "title": "The Hitchhiker's Guide to the Galaxy", + "author": "Douglas Adams", + "genre": "Science Fiction", + "published": 1979, + "rating": 4.2, + "tags": ["comedy", "space", "adventure"], // Array literal + "awards": ["hugo": true, "nebula": false], // Dictionary literal + "nestedField": ["level.1": ["level.2": true]], // Nested dictionary literal + ], + "book2": [ + "title": "Pride and Prejudice", + "author": "Jane Austen", + "genre": "Romance", + "published": 1813, + "rating": 4.5, + "tags": ["classic", "social commentary", "love"], + "awards": ["none": true], + ], + "book3": [ + "title": "One Hundred Years of Solitude", + "author": "Gabriel García Márquez", + "genre": "Magical Realism", + "published": 1967, + "rating": 4.3, + "tags": ["family", "history", "fantasy"], + "awards": ["nobel": true, "nebula": false], + ], + "book4": [ + "title": "The Lord of the Rings", + "author": "J.R.R. Tolkien", + "genre": "Fantasy", + "published": 1954, + "rating": 4.7, + "tags": ["adventure", "magic", "epic"], + "awards": ["hugo": false, "nebula": false], + ], + "book5": [ + "title": "The Handmaid's Tale", + "author": "Margaret Atwood", + "genre": "Dystopian", + "published": 1985, + "rating": 4.1, + "tags": ["feminism", "totalitarianism", "resistance"], + "awards": ["arthur c. clarke": true, "booker prize": false], + ], + "book6": [ + "title": "Crime and Punishment", + "author": "Fyodor Dostoevsky", + "genre": "Psychological Thriller", + "published": 1866, + "rating": 4.3, + "tags": ["philosophy", "crime", "redemption"], + "awards": ["none": true], + ], + "book7": [ + "title": "To Kill a Mockingbird", + "author": "Harper Lee", + "genre": "Southern Gothic", + "published": 1960, + "rating": 4.2, + "tags": ["racism", "injustice", "coming-of-age"], + "awards": ["pulitzer": true], + ], + "book8": [ + "title": "1984", + "author": "George Orwell", + "genre": "Dystopian", + "published": 1949, + "rating": 4.2, + "tags": ["surveillance", "totalitarianism", "propaganda"], + "awards": ["prometheus": true], + ], + "book9": [ + "title": "The Great Gatsby", + "author": "F. Scott Fitzgerald", + "genre": "Modernist", + "published": 1925, + "rating": 4.0, + "tags": ["wealth", "american dream", "love"], + "awards": ["none": true], + ], + "book10": [ + "title": "Dune", + "author": "Frank Herbert", + "genre": "Science Fiction", + "published": 1965, + "rating": 4.6, + "tags": ["politics", "desert", "ecology"], + "awards": ["hugo": true, "nebula": true], + ], +] + +enum RaceResult { + case success(T) + case timedOut +} + +/// Executes an async operation with a timeout. +/// +/// - Parameters: +/// - duration: The maximum time to wait for the operation to complete. +/// - operation: The async operation to perform. +/// - Returns: The result of the operation if it completes within the time limit, otherwise `nil`. +/// - Throws: An error if the `operation` itself throws an error before the timeout. +func withTimeout(nanoSeconds: UInt64, + operation: @escaping @Sendable () async throws -> T) async throws + -> T? { + return try await withThrowingTaskGroup(of: RaceResult.self) { group in + // Add a task for the long-running operation. + group.addTask { + let result = try await operation() + return .success(result) + } + + // Add a task that just sleeps for the duration. + group.addTask { + try await Task.sleep(nanoseconds: nanoSeconds) + return .timedOut + } + + // Await the first result that comes in. + guard let firstResult = try await group.next() else { + // This should not happen if the group has tasks. + return nil + } + + // Once we have a winner, cancel the other task. + // This is CRUCIAL to prevent the losing task from running forever. + group.cancelAll() + + // Switch on the result to return the value or nil. + switch firstResult { + case let .success(value): + return value + case .timedOut: + return nil + } + } +} + +@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *) +class RealtimePipelineIntegrationTests: FSTIntegrationTestCase { + override func setUp() { + FSTIntegrationTestCase.switchToEnterpriseMode() + super.setUp() + } + + func testBasicAsyncStream() async throws { + let db = self.db + let collRef = collectionRef() + writeAllDocuments(bookDocs, toCollection: collRef) + + let pipeline = db + .realtimePipeline() + .collection(collRef.path) + .where(Field("rating").greaterThanOrEqual(4.5)) + + let stream = pipeline.snapshotStream() + var iterator = stream.makeAsyncIterator() + + let firstSnapshot = try await iterator.next() + XCTAssertEqual(firstSnapshot!.metadata.isFromCache, true) + XCTAssertEqual(firstSnapshot!.results().count, 3) + XCTAssertEqual(firstSnapshot!.results().first?.get("title") as? String, "Dune") + XCTAssertEqual(firstSnapshot!.results()[1].get("title") as? String, "Pride and Prejudice") + XCTAssertEqual(firstSnapshot!.results()[2].get("title") as? String, "The Lord of the Rings") + + // dropping Dune out of the result set + try await collRef.document("book10").updateData(["rating": 4.4]) + let secondSnapshot = try await iterator.next() + XCTAssertEqual(secondSnapshot!.results().count, 2) + XCTAssertEqual(secondSnapshot!.results()[0].get("title") as? String, "Pride and Prejudice") + XCTAssertEqual(secondSnapshot!.results()[1].get("title") as? String, "The Lord of the Rings") + + // Adding book1 to the result + try await collRef.document("book1").updateData(["rating": 4.7]) + let thirdSnapshot = try await iterator.next() + XCTAssertEqual(thirdSnapshot!.results().count, 3) + XCTAssertEqual( + thirdSnapshot!.results()[0].get("title") as? String, + "The Hitchhiker's Guide to the Galaxy" + ) + + // Adding book1 to the result + try await collRef.document("book2").delete() + let fourthSnapshot = try await iterator.next() + XCTAssertEqual(fourthSnapshot!.results().count, 2) + XCTAssertEqual( + fourthSnapshot!.results()[0].get("title") as? String, + "The Hitchhiker's Guide to the Galaxy" + ) + XCTAssertEqual(fourthSnapshot!.results()[1].get("title") as? String, "The Lord of the Rings") + } + + func testResultChanges() async throws { + let collRef = collectionRef( + withDocuments: bookDocs + ) + let db = collRef.firestore + + let pipeline = db + .realtimePipeline() + .collection(collRef.path) + .where(Field("rating").greaterThanOrEqual(4.5)) + + let stream = pipeline.snapshotStream() + var iterator = stream.makeAsyncIterator() + + let firstSnapshot = try await iterator.next() + XCTAssertEqual(firstSnapshot!.changes.count, 3) + XCTAssertEqual(firstSnapshot!.changes.first?.result.get("title") as? String, "Dune") + XCTAssertEqual(firstSnapshot!.changes.first?.type, .added) + XCTAssertEqual(firstSnapshot!.changes[1].result.get("title") as? String, "Pride and Prejudice") + XCTAssertEqual(firstSnapshot!.changes[1].type, .added) + XCTAssertEqual( + firstSnapshot!.changes[2].result.get("title") as? String, + "The Lord of the Rings" + ) + XCTAssertEqual(firstSnapshot!.changes[2].type, .added) + + // dropping Dune out of the result set + try await collRef.document("book10").updateData(["rating": 4.4]) + let secondSnapshot = try await iterator.next() + XCTAssertEqual(secondSnapshot!.changes.count, 1) + XCTAssertEqual(secondSnapshot!.changes.first?.result.get("title") as? String, "Dune") + XCTAssertEqual(secondSnapshot!.changes.first?.type, .removed) + XCTAssertEqual(secondSnapshot!.changes.first?.oldIndex, 0) + XCTAssertEqual(secondSnapshot!.changes.first?.newIndex, nil) + + // Adding book1 to the result + try await collRef.document("book1").updateData(["rating": 4.7]) + let thirdSnapshot = try await iterator.next() + XCTAssertEqual(thirdSnapshot!.changes.count, 1) + XCTAssertEqual( + thirdSnapshot!.changes[0].result.get("title") as? String, + "The Hitchhiker's Guide to the Galaxy" + ) + XCTAssertEqual(thirdSnapshot!.changes[0].type, .added) + XCTAssertEqual(thirdSnapshot!.changes[0].oldIndex, nil) + XCTAssertEqual(thirdSnapshot!.changes[0].newIndex, 0) + + // Delete book 2 + try await collRef.document("book2").delete() + let fourthSnapshot = try await iterator.next() + XCTAssertEqual(fourthSnapshot!.changes.count, 1) + XCTAssertEqual( + fourthSnapshot!.changes[0].result.get("title") as? String, + "Pride and Prejudice" + ) + XCTAssertEqual(fourthSnapshot!.changes[0].oldIndex, 1) + XCTAssertEqual(fourthSnapshot!.changes[0].newIndex, nil) + } + + func testCanListenToCache() async throws { + let db = self.db + let collRef = collectionRef() + writeAllDocuments(bookDocs, toCollection: collRef) + + let pipeline = db + .realtimePipeline() + .collection(collRef.path) + .where(Field("rating").greaterThanOrEqual(4.5)) + + let stream = pipeline.snapshotStream( + options: PipelineListenOptions(includeMetadataChanges: true, source: .cache) + ) + + actor IteratorWrapper { + var iterator: AsyncThrowingStream.Iterator + init(_ iterator: AsyncThrowingStream.Iterator) { + self.iterator = iterator + } + + func next() async throws -> RealtimePipeline.Snapshot? { + var localIterator = iterator + defer { iterator = localIterator } + return try await localIterator.next() + } + } + let wrapper = IteratorWrapper(stream.makeAsyncIterator()) + + let firstSnapshot = try await wrapper.next() + XCTAssertEqual(firstSnapshot!.metadata.isFromCache, true) + XCTAssertEqual(firstSnapshot!.results().count, 3) + XCTAssertEqual(firstSnapshot!.results().first?.get("title") as? String, "Dune") + XCTAssertEqual(firstSnapshot!.results()[1].get("title") as? String, "Pride and Prejudice") + XCTAssertEqual(firstSnapshot!.results()[2].get("title") as? String, "The Lord of the Rings") + + disableNetwork() + enableNetwork() + + let duration: UInt64 = 100 * 1_000_000 // 100ms + let result = try await withTimeout(nanoSeconds: duration) { + try await wrapper.next() + } + + XCTAssertNil(result as Any?) + } + + func testCanListenToMetadataOnlyChanges() async throws { + let db = self.db + let collRef = collectionRef() + writeAllDocuments(bookDocs, toCollection: collRef) + + let pipeline = db + .realtimePipeline() + .collection(collRef.path) + .where(Field("rating").greaterThanOrEqual(4.5)) + + let stream = pipeline.snapshotStream( + options: PipelineListenOptions(includeMetadataChanges: true) + ) + var iterator = stream.makeAsyncIterator() + + let firstSnapshot = try await iterator.next() + XCTAssertEqual(firstSnapshot!.metadata.isFromCache, true) + XCTAssertEqual(firstSnapshot!.results().count, 3) + XCTAssertEqual(firstSnapshot!.results().first?.get("title") as? String, "Dune") + XCTAssertEqual(firstSnapshot!.results()[1].get("title") as? String, "Pride and Prejudice") + XCTAssertEqual(firstSnapshot!.results()[2].get("title") as? String, "The Lord of the Rings") + + disableNetwork() + enableNetwork() + + let secondSnapshot = try await iterator.next() + XCTAssertEqual(secondSnapshot!.metadata.isFromCache, false) + XCTAssertEqual(secondSnapshot!.results().count, 3) + XCTAssertEqual(secondSnapshot!.changes.count, 0) + } + + func testCanReadServerTimestampEstimateProperly() async throws { + let db = self.db + let collRef = collectionRef() + writeAllDocuments(bookDocs, toCollection: collRef) + + disableNetwork() + + Task { + try? await collRef.document("book1").updateData([ + "rating": FieldValue.serverTimestamp(), + ]) + } + + let stream = db.realtimePipeline().collection(collRef.path) + .where(Field("title").equal("The Hitchhiker's Guide to the Galaxy")) + .snapshotStream(options: PipelineListenOptions(serverTimestamps: .estimate)) + + var iterator = stream.makeAsyncIterator() + + let firstSnapshot = try await iterator.next() + let result = firstSnapshot!.results()[0] + XCTAssertEqual(firstSnapshot!.metadata.isFromCache, true) + XCTAssertNotNil(result.get("rating") as? Timestamp) + XCTAssertEqual(result.get("rating") as? Timestamp, result.data["rating"] as? Timestamp) + let firstChanges = firstSnapshot!.changes + XCTAssertEqual(firstChanges.count, 1) + XCTAssertEqual(firstChanges[0].type, .added) + XCTAssertNotNil(firstChanges[0].result.get("rating") as? Timestamp) + XCTAssertEqual( + firstChanges[0].result.get("rating") as? Timestamp, + result.get("rating") as? Timestamp + ) + + enableNetwork() + + let secondSnapshot = try await iterator.next() + XCTAssertEqual(secondSnapshot!.metadata.isFromCache, false) + XCTAssertNotEqual( + secondSnapshot!.results()[0].get("rating") as? Timestamp, + result.data["rating"] as? Timestamp + ) + let secondChanges = secondSnapshot!.changes + XCTAssertEqual(secondChanges.count, 1) + XCTAssertEqual(secondChanges[0].type, .modified) + XCTAssertNotNil(secondChanges[0].result.get("rating") as? Timestamp) + XCTAssertEqual( + secondChanges[0].result.get("rating") as? Timestamp, + secondSnapshot!.results()[0].get("rating") as? Timestamp + ) + } + + func testCanEvaluateServerTimestampEstimateProperly() async throws { + let db = self.db + let collRef = collectionRef() + writeAllDocuments(bookDocs, toCollection: collRef) + + disableNetwork() + + let now = Constant(Timestamp(date: Date())) + Task { + try? await collRef.document("book1").updateData([ + "rating": FieldValue.serverTimestamp(), + ]) + } + + let stream = db.realtimePipeline().collection(collRef.path) + .where( + Field("rating").timestampAdd(amount: Constant("second"), unit: Constant(1)).greaterThan(now) + ) + .snapshotStream( + options: PipelineListenOptions(serverTimestamps: .estimate, includeMetadataChanges: true) + ) + + var iterator = stream.makeAsyncIterator() + + let firstSnapshot = try await iterator.next() + let result = firstSnapshot!.results()[0] + XCTAssertEqual(firstSnapshot!.metadata.isFromCache, true) + XCTAssertNotNil(result.get("rating") as? Timestamp) + XCTAssertEqual(result.get("rating") as? Timestamp, result.data["rating"] as? Timestamp) + + // TODO(pipeline): Enable this when watch supports timestampAdd + // enableNetwork() + // + // let secondSnapshot = try await iterator.next() + // XCTAssertEqual(secondSnapshot!.metadata.isFromCache, false) + // XCTAssertNotEqual( + // secondSnapshot!.results()[0].get("rating") as? Timestamp, + // result.data["rating"] as? Timestamp + // ) + } + + func testCanReadServerTimestampPreviousProperly() async throws { + let db = self.db + let collRef = collectionRef() + writeAllDocuments(bookDocs, toCollection: collRef) + + disableNetwork() + + Task { + try? await collRef.document("book1").updateData([ + "rating": FieldValue.serverTimestamp(), + ]) + } + + let stream = db.realtimePipeline().collection(collRef.path) + .where(Field("title").equal("The Hitchhiker's Guide to the Galaxy")) + .snapshotStream(options: PipelineListenOptions(serverTimestamps: .previous)) + + var iterator = stream.makeAsyncIterator() + + let firstSnapshot = try await iterator.next() + let result = firstSnapshot!.results()[0] + XCTAssertEqual(firstSnapshot!.metadata.isFromCache, true) + XCTAssertNotNil(result.get("rating") as? Double) + XCTAssertEqual(result.get("rating") as! Double, 4.2) + XCTAssertEqual(result.get("rating") as! Double, result.data["rating"] as! Double) + let firstChanges = firstSnapshot!.changes + XCTAssertEqual(firstChanges.count, 1) + XCTAssertEqual(firstChanges[0].type, .added) + XCTAssertEqual(firstChanges[0].result.get("rating") as! Double, 4.2) + + enableNetwork() + + let secondSnapshot = try await iterator.next() + XCTAssertEqual(secondSnapshot!.metadata.isFromCache, false) + XCTAssertNotNil(secondSnapshot!.results()[0].get("rating") as? Timestamp) + let secondChanges = secondSnapshot!.changes + XCTAssertEqual(secondChanges.count, 1) + XCTAssertEqual(secondChanges[0].type, .modified) + XCTAssertNotNil(secondChanges[0].result.get("rating") as? Timestamp) + XCTAssertEqual( + secondChanges[0].result.get("rating") as? Timestamp, + secondSnapshot!.results()[0].get("rating") as? Timestamp + ) + } + + func testCanEvaluateServerTimestampPreviousProperly() async throws { + let db = self.db + let collRef = collectionRef() + writeAllDocuments(bookDocs, toCollection: collRef) + + disableNetwork() + + Task { + try? await collRef.document("book1").updateData([ + "title": FieldValue.serverTimestamp(), + ]) + } + + let stream = db.realtimePipeline().collection(collRef.path) + .where(Field("title").equal("The Hitchhiker's Guide to the Galaxy")) + .snapshotStream( + options: PipelineListenOptions(serverTimestamps: .previous) + ) + + var iterator = stream.makeAsyncIterator() + + let firstSnapshot = try await iterator.next() + let result = firstSnapshot!.results()[0] + XCTAssertEqual(firstSnapshot!.metadata.isFromCache, true) + XCTAssertEqual(result.get("title") as? String, "The Hitchhiker's Guide to the Galaxy") + + // TODO(pipeline): Enable this when watch supports timestampAdd + // enableNetwork() + } + + func testCanReadServerTimestampNoneProperly() async throws { + let db = self.db + let collRef = collectionRef() + writeAllDocuments(bookDocs, toCollection: collRef) + + disableNetwork() + + Task { + try? await collRef.document("book1").updateData([ + "rating": FieldValue.serverTimestamp(), + ]) + } + + let stream = db.realtimePipeline().collection(collRef.path) + .where(Field("title").equal("The Hitchhiker's Guide to the Galaxy")) + // .none is the default behavior + .snapshotStream() + + var iterator = stream.makeAsyncIterator() + + let firstSnapshot = try await iterator.next() + let result = firstSnapshot!.results()[0] + XCTAssertEqual(firstSnapshot!.metadata.isFromCache, true) + XCTAssertNil(result.get("rating") as? Timestamp) + XCTAssertEqual(result.get("rating") as? Timestamp, result.data["rating"] as? Timestamp) + let firstChanges = firstSnapshot!.changes + XCTAssertEqual(firstChanges.count, 1) + XCTAssertEqual(firstChanges[0].type, .added) + XCTAssertNil(firstChanges[0].result.get("rating") as? Timestamp) + + enableNetwork() + + let secondSnapshot = try await iterator.next() + XCTAssertEqual(secondSnapshot!.metadata.isFromCache, false) + XCTAssertNotNil(secondSnapshot!.results()[0].get("rating") as? Timestamp) + let secondChanges = secondSnapshot!.changes + XCTAssertEqual(secondChanges.count, 1) + XCTAssertEqual(secondChanges[0].type, .modified) + XCTAssertNotNil(secondChanges[0].result.get("rating") as? Timestamp) + XCTAssertEqual( + secondChanges[0].result.get("rating") as? Timestamp, + secondSnapshot!.results()[0].get("rating") as? Timestamp + ) + } + + func testCanEvaluateServerTimestampNoneProperly() async throws { + let db = self.db + let collRef = collectionRef() + writeAllDocuments(bookDocs, toCollection: collRef) + + disableNetwork() + + Task { + try? await collRef.document("book1").updateData([ + "title": FieldValue.serverTimestamp(), + ]) + } + + let stream = db.realtimePipeline().collection(collRef.path) + .where(Field("title").equal(Constant.nil)) + .snapshotStream( + ) + + var iterator = stream.makeAsyncIterator() + + let firstSnapshot = try await iterator.next() + let result = firstSnapshot!.results()[0] + XCTAssertEqual(firstSnapshot!.metadata.isFromCache, true) + XCTAssertNil(result.get("title") as? String) + + // TODO(pipeline): Enable this when watch supports timestampAdd + // enableNetwork() + } + + func testSamePipelineWithDifferetnOptions() async throws { + let db = self.db + let collRef = collectionRef() + writeAllDocuments(bookDocs, toCollection: collRef) + + disableNetwork() + + Task { + try? await collRef.document("book1").updateData([ + "title": FieldValue.serverTimestamp(), + ]) + } + + let pipeline = db.realtimePipeline().collection(collRef.path) + .where(Field("title").notEqual(Constant.nil)) + .limit(1) + + let stream1 = pipeline + .snapshotStream( + options: PipelineListenOptions(serverTimestamps: .previous) + ) + + var iterator1 = stream1.makeAsyncIterator() + + let firstSnapshot1 = try await iterator1.next() + var result1 = firstSnapshot1!.results()[0] + XCTAssertEqual(firstSnapshot1!.metadata.isFromCache, true) + XCTAssertEqual(result1.get("title") as? String, "The Hitchhiker's Guide to the Galaxy") + + let stream2 = pipeline + .snapshotStream( + options: PipelineListenOptions(serverTimestamps: .estimate) + ) + + var iterator2 = stream2.makeAsyncIterator() + + let firstSnapshot2 = try await iterator2.next() + var result2 = firstSnapshot2!.results()[0] + XCTAssertEqual(firstSnapshot2!.metadata.isFromCache, true) + XCTAssertNotNil(result2.get("title") as? Timestamp) + + enableNetwork() + + let secondSnapshot1 = try await iterator1.next() + result1 = secondSnapshot1!.results()[0] + XCTAssertEqual(secondSnapshot1!.metadata.isFromCache, false) + XCTAssertNotNil(result1.get("title") as? Timestamp) + + let secondSnapshot2 = try await iterator2.next() + result2 = secondSnapshot2!.results()[0] + XCTAssertEqual(secondSnapshot2!.metadata.isFromCache, false) + XCTAssertNotNil(result2.get("title") as? Timestamp) + } +} diff --git a/Firestore/core/src/core/expressions_eval.cc b/Firestore/core/src/core/expressions_eval.cc index cdc8c9bd7f0..757172c274c 100644 --- a/Firestore/core/src/core/expressions_eval.cc +++ b/Firestore/core/src/core/expressions_eval.cc @@ -201,8 +201,8 @@ EvaluateResult EvaluateResult::NewValue( std::unique_ptr FunctionToEvaluable( const api::FunctionExpr& function) { - if (function.name() == "eq") { - return std::make_unique(function); + if (function.name() == "equal") { + return std::make_unique(function); } else if (function.name() == "add") { return std::make_unique(function); } else if (function.name() == "subtract") { @@ -213,16 +213,16 @@ std::unique_ptr FunctionToEvaluable( return std::make_unique(function); } else if (function.name() == "mod") { return std::make_unique(function); - } else if (function.name() == "neq") { - return std::make_unique(function); - } else if (function.name() == "lt") { - return std::make_unique(function); - } else if (function.name() == "lte") { - return std::make_unique(function); - } else if (function.name() == "gt") { - return std::make_unique(function); - } else if (function.name() == "gte") { - return std::make_unique(function); + } else if (function.name() == "not_equal") { + return std::make_unique(function); + } else if (function.name() == "less_than") { + return std::make_unique(function); + } else if (function.name() == "less_than_or_equal") { + return std::make_unique(function); + } else if (function.name() == "greater_than") { + return std::make_unique(function); + } else if (function.name() == "greater_than_or_equal") { + return std::make_unique(function); } else if (function.name() == "array_reverse") { // Removed array_concat return std::make_unique(function); } else if (function.name() == "array_contains") { @@ -245,9 +245,9 @@ std::unique_ptr FunctionToEvaluable( return std::make_unique(function); } else if (function.name() == "cond") { return std::make_unique(function); - } else if (function.name() == "eq_any") { + } else if (function.name() == "equal_any") { return std::make_unique(function); - } else if (function.name() == "not_eq_any") { + } else if (function.name() == "not_equal_any") { return std::make_unique(function); } else if (function.name() == "is_nan") { return std::make_unique(function); @@ -259,33 +259,32 @@ std::unique_ptr FunctionToEvaluable( return std::make_unique(function); } else if (function.name() == "is_error") { return std::make_unique(function); - } else if (function.name() == "logical_maximum") { - return std::make_unique(function); - } else if (function.name() == "logical_minimum") { - return std::make_unique(function); + } else if (function.name() == "maximum") { + return std::make_unique(function); + } else if (function.name() == "minimum") { + return std::make_unique(function); } else if (function.name() == "map_get") { return std::make_unique(function); } else if (function.name() == "byte_length") { return std::make_unique(function); } else if (function.name() == "char_length") { return std::make_unique(function); - } else if (function.name() == "str_concat") { - return std::make_unique(function); + } else if (function.name() == "string_concat") { + return std::make_unique(function); } else if (function.name() == "ends_with") { return std::make_unique(function); } else if (function.name() == "starts_with") { return std::make_unique(function); - } else if (function.name() == "str_contains") { - return std::make_unique(function); + } else if (function.name() == "string_contains") { + return std::make_unique(function); } else if (function.name() == "to_lower") { return std::make_unique(function); } else if (function.name() == "to_upper") { return std::make_unique(function); } else if (function.name() == "trim") { return std::make_unique(function); - } else if (function.name() == "reverse") { - // Note: This handles string reverse. Array reverse is separate. - return std::make_unique(function); + } else if (function.name() == "string_reverse") { + return std::make_unique(function); } else if (function.name() == "regex_contains") { return std::make_unique(function); } else if (function.name() == "regex_match") { @@ -427,8 +426,8 @@ EvaluateResult ComparisonBase::Evaluate( return CompareToResult(left, right); } -EvaluateResult CoreEq::CompareToResult(const EvaluateResult& left, - const EvaluateResult& right) const { +EvaluateResult CoreEqual::CompareToResult(const EvaluateResult& left, + const EvaluateResult& right) const { // Type mismatch always results in false for Eq if (model::GetTypeOrder(*left.value()) != model::GetTypeOrder(*right.value())) { @@ -450,8 +449,8 @@ EvaluateResult CoreEq::CompareToResult(const EvaluateResult& left, HARD_FAIL("Unhandled case in switch statement"); } -EvaluateResult CoreNeq::CompareToResult(const EvaluateResult& left, - const EvaluateResult& right) const { +EvaluateResult CoreNotEqual::CompareToResult( + const EvaluateResult& left, const EvaluateResult& right) const { // NaN != anything (including NaN) is true if (model::IsNaNValue(*left.value()) || model::IsNaNValue(*right.value())) { return EvaluateResult::NewValue(nanopb::MakeMessage(model::TrueValue())); @@ -473,8 +472,8 @@ EvaluateResult CoreNeq::CompareToResult(const EvaluateResult& left, HARD_FAIL("Unhandled case in switch statement"); } -EvaluateResult CoreLt::CompareToResult(const EvaluateResult& left, - const EvaluateResult& right) const { +EvaluateResult CoreLessThan::CompareToResult( + const EvaluateResult& left, const EvaluateResult& right) const { // Type mismatch always results in false if (model::GetTypeOrder(*left.value()) != model::GetTypeOrder(*right.value())) { @@ -491,8 +490,8 @@ EvaluateResult CoreLt::CompareToResult(const EvaluateResult& left, nanopb::MakeMessage(result ? model::TrueValue() : model::FalseValue())); } -EvaluateResult CoreLte::CompareToResult(const EvaluateResult& left, - const EvaluateResult& right) const { +EvaluateResult CoreLessThanOrEqual::CompareToResult( + const EvaluateResult& left, const EvaluateResult& right) const { // Type mismatch always results in false if (model::GetTypeOrder(*left.value()) != model::GetTypeOrder(*right.value())) { @@ -516,8 +515,8 @@ EvaluateResult CoreLte::CompareToResult(const EvaluateResult& left, nanopb::MakeMessage(result ? model::TrueValue() : model::FalseValue())); } -EvaluateResult CoreGt::CompareToResult(const EvaluateResult& left, - const EvaluateResult& right) const { +EvaluateResult CoreGreaterThan::CompareToResult( + const EvaluateResult& left, const EvaluateResult& right) const { // Type mismatch always results in false if (model::GetTypeOrder(*left.value()) != model::GetTypeOrder(*right.value())) { @@ -534,8 +533,8 @@ EvaluateResult CoreGt::CompareToResult(const EvaluateResult& left, nanopb::MakeMessage(result ? model::TrueValue() : model::FalseValue())); } -EvaluateResult CoreGte::CompareToResult(const EvaluateResult& left, - const EvaluateResult& right) const { +EvaluateResult CoreGreaterThanOrEqual::CompareToResult( + const EvaluateResult& left, const EvaluateResult& right) const { // Type mismatch always results in false if (model::GetTypeOrder(*left.value()) != model::GetTypeOrder(*right.value())) { @@ -881,7 +880,7 @@ EvaluateResult CoreCharLength::Evaluate( } } -EvaluateResult CoreStrConcat::Evaluate( +EvaluateResult CoreStringConcat::Evaluate( const api::EvaluateContext& context, const model::PipelineInputOutput& document) const { std::string result_string; @@ -928,8 +927,8 @@ EvaluateResult CoreStartsWith::PerformSearch(const std::string& value, nanopb::MakeMessage(result ? model::TrueValue() : model::FalseValue())); } -EvaluateResult CoreStrContains::PerformSearch(const std::string& value, - const std::string& search) const { +EvaluateResult CoreStringContains::PerformSearch( + const std::string& value, const std::string& search) const { // Use absl::StrContains bool result = absl::StrContains(value, search); return EvaluateResult::NewValue( @@ -1001,7 +1000,7 @@ EvaluateResult CoreTrim::Evaluate( } } -EvaluateResult CoreReverse::Evaluate( +EvaluateResult CoreStringReverse::Evaluate( const api::EvaluateContext& context, const model::PipelineInputOutput& document) const { HARD_ASSERT(expr_->params().size() == 1, @@ -1293,9 +1292,9 @@ EvaluateResult CoreArrayContains::Evaluate( std::vector> reversed_params( expr_->params().rbegin(), expr_->params().rend()); - auto const eq_any = - CoreEqAny(api::FunctionExpr("eq_any", std::move(reversed_params))); - return eq_any.Evaluate(context, document); + auto const equal_any = + CoreEqAny(api::FunctionExpr("equal_any", std::move(reversed_params))); + return equal_any.Evaluate(context, document); } EvaluateResult CoreArrayContainsAll::Evaluate( @@ -1690,9 +1689,10 @@ EvaluateResult CoreCond::Evaluate( EvaluateResult CoreEqAny::Evaluate( const api::EvaluateContext& context, const model::PipelineInputOutput& document) const { - HARD_ASSERT(expr_->params().size() == 2, - "eq_any() function requires exactly 2 params (search value and " - "array value)"); + HARD_ASSERT( + expr_->params().size() == 2, + "equal_any() function requires exactly 2 params (search value and " + "array value)"); bool found_null = false; @@ -1763,7 +1763,8 @@ EvaluateResult CoreNotEqAny::Evaluate( "array value)"); CoreNot equivalent(api::FunctionExpr( - "not", {std::make_shared("eq_any", expr_->params())})); + "not", + {std::make_shared("equal_any", expr_->params())})); return equivalent.Evaluate(context, document); } @@ -1853,7 +1854,7 @@ EvaluateResult CoreIsError::Evaluate( } } -EvaluateResult CoreLogicalMaximum::Evaluate( +EvaluateResult CoreMaximum::Evaluate( const api::EvaluateContext& context, const model::PipelineInputOutput& document) const { // Store the underlying Value proto in the optional, not EvaluateResult @@ -1887,7 +1888,7 @@ EvaluateResult CoreLogicalMaximum::Evaluate( return EvaluateResult::NewNull(); } -EvaluateResult CoreLogicalMinimum::Evaluate( +EvaluateResult CoreMinimum::Evaluate( const api::EvaluateContext& context, const model::PipelineInputOutput& document) const { // Store the underlying Value proto in the optional, not EvaluateResult diff --git a/Firestore/core/src/core/expressions_eval.h b/Firestore/core/src/core/expressions_eval.h index c82060a7cb7..298d3e8b617 100644 --- a/Firestore/core/src/core/expressions_eval.h +++ b/Firestore/core/src/core/expressions_eval.h @@ -163,9 +163,9 @@ class ComparisonBase : public EvaluableExpr { std::unique_ptr expr_; }; -class CoreEq : public ComparisonBase { +class CoreEqual : public ComparisonBase { public: - explicit CoreEq(const api::FunctionExpr& expr) : ComparisonBase(expr) { + explicit CoreEqual(const api::FunctionExpr& expr) : ComparisonBase(expr) { } protected: @@ -173,9 +173,9 @@ class CoreEq : public ComparisonBase { const EvaluateResult& right) const override; }; -class CoreNeq : public ComparisonBase { +class CoreNotEqual : public ComparisonBase { public: - explicit CoreNeq(const api::FunctionExpr& expr) : ComparisonBase(expr) { + explicit CoreNotEqual(const api::FunctionExpr& expr) : ComparisonBase(expr) { } protected: @@ -183,9 +183,9 @@ class CoreNeq : public ComparisonBase { const EvaluateResult& right) const override; }; -class CoreLt : public ComparisonBase { +class CoreLessThan : public ComparisonBase { public: - explicit CoreLt(const api::FunctionExpr& expr) : ComparisonBase(expr) { + explicit CoreLessThan(const api::FunctionExpr& expr) : ComparisonBase(expr) { } protected: @@ -193,9 +193,10 @@ class CoreLt : public ComparisonBase { const EvaluateResult& right) const override; }; -class CoreLte : public ComparisonBase { +class CoreLessThanOrEqual : public ComparisonBase { public: - explicit CoreLte(const api::FunctionExpr& expr) : ComparisonBase(expr) { + explicit CoreLessThanOrEqual(const api::FunctionExpr& expr) + : ComparisonBase(expr) { } protected: @@ -203,9 +204,10 @@ class CoreLte : public ComparisonBase { const EvaluateResult& right) const override; }; -class CoreGt : public ComparisonBase { +class CoreGreaterThan : public ComparisonBase { public: - explicit CoreGt(const api::FunctionExpr& expr) : ComparisonBase(expr) { + explicit CoreGreaterThan(const api::FunctionExpr& expr) + : ComparisonBase(expr) { } protected: @@ -213,9 +215,10 @@ class CoreGt : public ComparisonBase { const EvaluateResult& right) const override; }; -class CoreGte : public ComparisonBase { +class CoreGreaterThanOrEqual : public ComparisonBase { public: - explicit CoreGte(const api::FunctionExpr& expr) : ComparisonBase(expr) { + explicit CoreGreaterThanOrEqual(const api::FunctionExpr& expr) + : ComparisonBase(expr) { } protected: @@ -431,9 +434,9 @@ class CoreCharLength : public EvaluableExpr { std::unique_ptr expr_; }; -class CoreStrConcat : public EvaluableExpr { +class CoreStringConcat : public EvaluableExpr { public: - explicit CoreStrConcat(const api::FunctionExpr& expr) + explicit CoreStringConcat(const api::FunctionExpr& expr) : expr_(std::make_unique(expr)) { } EvaluateResult Evaluate( @@ -466,9 +469,9 @@ class CoreStartsWith : public StringSearchBase { const std::string& search) const override; }; -class CoreStrContains : public StringSearchBase { +class CoreStringContains : public StringSearchBase { public: - explicit CoreStrContains(const api::FunctionExpr& expr) + explicit CoreStringContains(const api::FunctionExpr& expr) : StringSearchBase(expr) { } @@ -516,9 +519,9 @@ class CoreTrim : public EvaluableExpr { std::unique_ptr expr_; }; -class CoreReverse : public EvaluableExpr { +class CoreStringReverse : public EvaluableExpr { public: - explicit CoreReverse(const api::FunctionExpr& expr) + explicit CoreStringReverse(const api::FunctionExpr& expr) : expr_(std::make_unique(expr)) { } EvaluateResult Evaluate( @@ -721,9 +724,9 @@ class CoreIsError : public EvaluableExpr { std::unique_ptr expr_; }; -class CoreLogicalMaximum : public EvaluableExpr { +class CoreMaximum : public EvaluableExpr { public: - explicit CoreLogicalMaximum(const api::FunctionExpr& expr) + explicit CoreMaximum(const api::FunctionExpr& expr) : expr_(std::make_unique(expr)) { } EvaluateResult Evaluate( @@ -734,9 +737,9 @@ class CoreLogicalMaximum : public EvaluableExpr { std::unique_ptr expr_; }; -class CoreLogicalMinimum : public EvaluableExpr { +class CoreMinimum : public EvaluableExpr { public: - explicit CoreLogicalMinimum(const api::FunctionExpr& expr) + explicit CoreMinimum(const api::FunctionExpr& expr) : expr_(std::make_unique(expr)) { } EvaluateResult Evaluate( diff --git a/Firestore/core/src/core/pipeline_util.cc b/Firestore/core/src/core/pipeline_util.cc index 11531845d32..212a801f1bc 100644 --- a/Firestore/core/src/core/pipeline_util.cc +++ b/Firestore/core/src/core/pipeline_util.cc @@ -561,22 +561,22 @@ std::shared_ptr ToPipelineBooleanExpr(const Filter& filter) { switch (op) { case FieldFilter::Operator::LessThan: - func_name = "lt"; + func_name = "less_than"; break; case FieldFilter::Operator::LessThanOrEqual: - func_name = "lte"; + func_name = "less_than_or_equal"; break; case FieldFilter::Operator::GreaterThan: - func_name = "gt"; + func_name = "greater_than"; break; case FieldFilter::Operator::GreaterThanOrEqual: - func_name = "gte"; + func_name = "greater_than_or_equal"; break; case FieldFilter::Operator::Equal: - func_name = "eq"; + func_name = "equal"; break; case FieldFilter::Operator::NotEqual: - func_name = "neq"; + func_name = "not_equal"; break; case FieldFilter::Operator::ArrayContains: func_name = "array_contains"; @@ -589,9 +589,9 @@ std::shared_ptr ToPipelineBooleanExpr(const Filter& filter) { "Value for IN, NOT_IN, ARRAY_CONTAINS_ANY must be an array."); if (op == FieldFilter::Operator::In) - func_name = "eq_any"; + func_name = "equal_any"; else if (op == FieldFilter::Operator::NotIn) - func_name = "not_eq_any"; + func_name = "not_equal_any"; else if (op == FieldFilter::Operator::ArrayContainsAny) func_name = "array_contains_any"; break; @@ -635,8 +635,9 @@ std::shared_ptr WhereConditionsFromCursor( std::make_shared(model::DeepClone(pos->values[i]))); } - std::string func_name = is_before ? "lt" : "gt"; - std::string func_inclusive_name = is_before ? "lte" : "gte"; + std::string func_name = is_before ? "less_than" : "greater_than"; + std::string func_inclusive_name = + is_before ? "less_than_or_equal" : "greater_than_or_equal"; std::vector> or_conditions; for (size_t sub_end = 1; sub_end <= cursors.size(); ++sub_end) { diff --git a/Firestore/core/test/unit/core/expressions/comparison_test.cc b/Firestore/core/test/unit/core/expressions/comparison_test.cc index 1113fd5d4b6..141b803941c 100644 --- a/Firestore/core/test/unit/core/expressions/comparison_test.cc +++ b/Firestore/core/test/unit/core/expressions/comparison_test.cc @@ -26,7 +26,7 @@ #include "Firestore/core/src/model/database_id.h" // For DatabaseId #include "Firestore/core/src/model/document_key.h" // For DocumentKey #include "Firestore/core/src/model/value_util.h" // For value constants like NaNValue, TypeOrder, NullValue, CanonicalId, Equals -#include "Firestore/core/test/unit/testutil/expression_test_util.h" // For EvaluateExpr, EqExpr, ComparisonValueTestData, RefConstant etc. +#include "Firestore/core/test/unit/testutil/expression_test_util.h" // For EvaluateExpr, EqualExpr, ComparisonValueTestData, RefConstant etc. #include "Firestore/core/test/unit/testutil/testutil.h" // For test helpers like Value, Array, Map, BlobValue, Doc #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -42,13 +42,13 @@ using model::MutableDocument; // Used as PipelineInputOutput alias using testing::_; // Explicitly qualify testutil helpers to avoid ambiguity using testutil::ComparisonValueTestData; -using testutil::EqExpr; +using testutil::EqualExpr; using testutil::EvaluateExpr; -using testutil::GteExpr; -using testutil::GtExpr; -using testutil::LteExpr; -using testutil::LtExpr; -using testutil::NeqExpr; +using testutil::GreaterThanExpr; +using testutil::GreaterThanOrEqualExpr; +using testutil::LessThanExpr; +using testutil::LessThanOrEqualExpr; +using testutil::NotEqualExpr; using testutil::RefConstant; using testutil::Returns; using testutil::ReturnsError; @@ -61,8 +61,8 @@ class ComparisonExpressionsTest : public ::testing::Test { // Helper moved to expression_test_util.h }; -// Fixture for Eq function tests -class EqFunctionTest : public ComparisonExpressionsTest {}; +// Fixture for Equal function tests +class EqualFunctionTest : public ComparisonExpressionsTest {}; // Helper to get canonical ID for logging, handling potential non-constant exprs std::string ExprId(const std::shared_ptr& expr) { @@ -75,95 +75,95 @@ std::string ExprId(const std::shared_ptr& expr) { return ""; } -TEST_F(EqFunctionTest, EquivalentValuesReturnTrue) { +TEST_F(EqualFunctionTest, EquivalentValuesReturnTrue) { for (const auto& pair : ComparisonValueTestData::EquivalentValues()) { - EXPECT_THAT(EvaluateExpr(*EqExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*EqualExpr({pair.first, pair.second})), Returns(testutil::Value(true))) - << "eq(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "equal(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; } } -TEST_F(EqFunctionTest, LessThanValuesReturnFalse) { +TEST_F(EqualFunctionTest, LessThanValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::LessThanValues()) { - EXPECT_THAT(EvaluateExpr(*EqExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*EqualExpr({pair.first, pair.second})), Returns(testutil::Value(false))) - << "eq(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "equal(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; } } -TEST_F(EqFunctionTest, GreaterThanValuesReturnFalse) { +TEST_F(EqualFunctionTest, GreaterThanValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::GreaterThanValues()) { - EXPECT_THAT(EvaluateExpr(*EqExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*EqualExpr({pair.first, pair.second})), Returns(testutil::Value(false))) - << "eq(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "equal(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; } } -TEST_F(EqFunctionTest, MixedTypeValuesReturnFalse) { +TEST_F(EqualFunctionTest, MixedTypeValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::MixedTypeValues()) { - EXPECT_THAT(EvaluateExpr(*EqExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*EqualExpr({pair.first, pair.second})), Returns(testutil::Value(false))) - << "eq(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "equal(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; } } -// --- Specific Eq Tests (Null, NaN, Missing, Error) --- +// --- Specific Equal Tests (Null, NaN, Missing, Error) --- -// Fixture for Neq function tests -class NeqFunctionTest : public ComparisonExpressionsTest {}; +// Fixture for NotEqual function tests +class NotEqualFunctionTest : public ComparisonExpressionsTest {}; -// Fixture for Lt function tests -class LtFunctionTest : public ComparisonExpressionsTest {}; +// Fixture for LessThan function tests +class LessThanFunctionTest : public ComparisonExpressionsTest {}; -// Fixture for Lte function tests -class LteFunctionTest : public ComparisonExpressionsTest {}; +// Fixture for LessThanOrEqual function tests +class LessThanOrEqualFunctionTest : public ComparisonExpressionsTest {}; -// Fixture for Gt function tests -class GtFunctionTest : public ComparisonExpressionsTest {}; +// Fixture for GreaterThan function tests +class GreaterThanFunctionTest : public ComparisonExpressionsTest {}; -// Fixture for Gte function tests -class GteFunctionTest : public ComparisonExpressionsTest {}; +// Fixture for GreaterThanOrEqual function tests +class GreaterThanOrEqualFunctionTest : public ComparisonExpressionsTest {}; -// --- Eq (==) Tests --- +// --- Equal (==) Tests --- -TEST_F(EqFunctionTest, NullEqualsNullReturnsNull) { - EXPECT_THAT(EvaluateExpr(*EqExpr({SharedConstant(model::NullValue()), - SharedConstant(model::NullValue())})), +TEST_F(EqualFunctionTest, NullEqualsNullReturnsNull) { + EXPECT_THAT(EvaluateExpr(*EqualExpr({SharedConstant(model::NullValue()), + SharedConstant(model::NullValue())})), ReturnsNull()); } // Corresponds to eq.null_any_returnsNull in typescript -TEST_F(EqFunctionTest, NullOperandReturnsNull) { +TEST_F(EqualFunctionTest, NullOperandReturnsNull) { for (const auto& val : ComparisonValueTestData::AllSupportedComparableValues()) { EXPECT_THAT( - EvaluateExpr(*EqExpr({SharedConstant(model::NullValue()), val})), + EvaluateExpr(*EqualExpr({SharedConstant(model::NullValue()), val})), ReturnsNull()) - << "eq(null, " << ExprId(val) << ")"; + << "equal(null, " << ExprId(val) << ")"; EXPECT_THAT( - EvaluateExpr(*EqExpr({val, SharedConstant(model::NullValue())})), + EvaluateExpr(*EqualExpr({val, SharedConstant(model::NullValue())})), ReturnsNull()) - << "eq(" << ExprId(val) << ", null)"; + << "equal(" << ExprId(val) << ", null)"; } EXPECT_THAT( - EvaluateExpr(*EqExpr({SharedConstant(model::NullValue()), - std::make_shared("nonexistent")})), + EvaluateExpr(*EqualExpr({SharedConstant(model::NullValue()), + std::make_shared("nonexistent")})), ReturnsError()); } // Corresponds to eq.nan tests in typescript -TEST_F(EqFunctionTest, NaNComparisonsReturnFalse) { +TEST_F(EqualFunctionTest, NaNComparisonsReturnFalse) { auto nan_expr = SharedConstant(std::numeric_limits::quiet_NaN()); - EXPECT_THAT(EvaluateExpr(*EqExpr({nan_expr, nan_expr})), + EXPECT_THAT(EvaluateExpr(*EqualExpr({nan_expr, nan_expr})), Returns(testutil::Value(false))); // NaN == NaN is false for (const auto& num_val : ComparisonValueTestData::NumericValues()) { - EXPECT_THAT(EvaluateExpr(*EqExpr({nan_expr, num_val})), + EXPECT_THAT(EvaluateExpr(*EqualExpr({nan_expr, num_val})), Returns(testutil::Value(false))) - << "eq(NaN, " << ExprId(num_val) << ")"; - EXPECT_THAT(EvaluateExpr(*EqExpr({num_val, nan_expr})), + << "equal(NaN, " << ExprId(num_val) << ")"; + EXPECT_THAT(EvaluateExpr(*EqualExpr({num_val, nan_expr})), Returns(testutil::Value(false))) - << "eq(" << ExprId(num_val) << ", NaN)"; + << "equal(" << ExprId(num_val) << ", NaN)"; } for (const auto& other_val : @@ -176,23 +176,23 @@ TEST_F(EqFunctionTest, NaNComparisonsReturnFalse) { } } if (!is_numeric) { - EXPECT_THAT(EvaluateExpr(*EqExpr({nan_expr, other_val})), + EXPECT_THAT(EvaluateExpr(*EqualExpr({nan_expr, other_val})), Returns(testutil::Value(false))) - << "eq(NaN, " << ExprId(other_val) << ")"; - EXPECT_THAT(EvaluateExpr(*EqExpr({other_val, nan_expr})), + << "equal(NaN, " << ExprId(other_val) << ")"; + EXPECT_THAT(EvaluateExpr(*EqualExpr({other_val, nan_expr})), Returns(testutil::Value(false))) - << "eq(" << ExprId(other_val) << ", NaN)"; + << "equal(" << ExprId(other_val) << ", NaN)"; } } + EXPECT_THAT(EvaluateExpr(*EqualExpr( + {SharedConstant(testutil::Array(testutil::Value( + std::numeric_limits::quiet_NaN()))), + SharedConstant(testutil::Array(testutil::Value( + std::numeric_limits::quiet_NaN())))})), + Returns(testutil::Value(false))); EXPECT_THAT( - EvaluateExpr(*EqExpr({SharedConstant(testutil::Array(testutil::Value( - std::numeric_limits::quiet_NaN()))), - SharedConstant(testutil::Array(testutil::Value( - std::numeric_limits::quiet_NaN())))})), - Returns(testutil::Value(false))); - EXPECT_THAT( - EvaluateExpr(*EqExpr( + EvaluateExpr(*EqualExpr( {SharedConstant(testutil::Map( "foo", testutil::Value(std::numeric_limits::quiet_NaN()))), @@ -204,148 +204,153 @@ TEST_F(EqFunctionTest, NaNComparisonsReturnFalse) { // Corresponds to eq.nullInArray_equality / eq.nullInMap_equality / // eq.null_missingInMap_equality -TEST_F(EqFunctionTest, NullContainerEquality) { +TEST_F(EqualFunctionTest, NullContainerEquality) { auto null_array = SharedConstant(testutil::Array(testutil::Value(nullptr))); - EXPECT_THAT(EvaluateExpr(*EqExpr( + EXPECT_THAT(EvaluateExpr(*EqualExpr( {null_array, SharedConstant(static_cast(1LL))})), Returns(testutil::Value(false))); - EXPECT_THAT(EvaluateExpr(*EqExpr({null_array, SharedConstant("1")})), + EXPECT_THAT(EvaluateExpr(*EqualExpr({null_array, SharedConstant("1")})), Returns(testutil::Value(false))); - EXPECT_THAT( - EvaluateExpr(*EqExpr({null_array, SharedConstant(model::NullValue())})), - ReturnsNull()); - EXPECT_THAT(EvaluateExpr(*EqExpr( + EXPECT_THAT(EvaluateExpr( + *EqualExpr({null_array, SharedConstant(model::NullValue())})), + ReturnsNull()); + EXPECT_THAT(EvaluateExpr(*EqualExpr( {null_array, SharedConstant(std::numeric_limits::quiet_NaN())})), Returns(testutil::Value(false))); EXPECT_THAT( - EvaluateExpr(*EqExpr({null_array, SharedConstant(testutil::Array())})), + EvaluateExpr(*EqualExpr({null_array, SharedConstant(testutil::Array())})), Returns(testutil::Value(false))); EXPECT_THAT( - EvaluateExpr(*EqExpr( + EvaluateExpr(*EqualExpr( {null_array, SharedConstant(testutil::Array(testutil::Value( std::numeric_limits::quiet_NaN())))})), ReturnsNull()); EXPECT_THAT( - EvaluateExpr(*EqExpr({null_array, SharedConstant(testutil::Array( - testutil::Value(nullptr)))})), + EvaluateExpr(*EqualExpr({null_array, SharedConstant(testutil::Array( + testutil::Value(nullptr)))})), ReturnsNull()); auto null_map = SharedConstant(testutil::Map("foo", testutil::Value(nullptr))); + EXPECT_THAT(EvaluateExpr(*EqualExpr( + {null_map, SharedConstant(testutil::Map( + "foo", testutil::Value(nullptr)))})), + ReturnsNull()); EXPECT_THAT( - EvaluateExpr(*EqExpr({null_map, SharedConstant(testutil::Map( - "foo", testutil::Value(nullptr)))})), - ReturnsNull()); - EXPECT_THAT( - EvaluateExpr(*EqExpr({null_map, SharedConstant(testutil::Map())})), + EvaluateExpr(*EqualExpr({null_map, SharedConstant(testutil::Map())})), Returns(testutil::Value(false))); } // Corresponds to eq.error_ tests -TEST_F(EqFunctionTest, ErrorHandling) { +TEST_F(EqualFunctionTest, ErrorHandling) { auto error_expr = std::make_shared("a.b"); auto non_map_input = testutil::Doc("coll/doc", 1, testutil::Map("a", 123)); for (const auto& val : ComparisonValueTestData::AllSupportedComparableValues()) { - EXPECT_THAT(EvaluateExpr(*EqExpr({error_expr, val}), non_map_input), + EXPECT_THAT(EvaluateExpr(*EqualExpr({error_expr, val}), non_map_input), ReturnsError()); - EXPECT_THAT(EvaluateExpr(*EqExpr({val, error_expr}), non_map_input), + EXPECT_THAT(EvaluateExpr(*EqualExpr({val, error_expr}), non_map_input), ReturnsError()); } - EXPECT_THAT(EvaluateExpr(*EqExpr({error_expr, error_expr}), non_map_input), + EXPECT_THAT(EvaluateExpr(*EqualExpr({error_expr, error_expr}), non_map_input), ReturnsError()); EXPECT_THAT( - EvaluateExpr(*EqExpr({error_expr, SharedConstant(model::NullValue())}), + EvaluateExpr(*EqualExpr({error_expr, SharedConstant(model::NullValue())}), non_map_input), ReturnsError()); } -TEST_F(EqFunctionTest, MissingFieldReturnsError) { - EXPECT_THAT(EvaluateExpr(*EqExpr({std::make_shared("nonexistent"), - SharedConstant(testutil::Value(1LL))})), - ReturnsError()); +TEST_F(EqualFunctionTest, MissingFieldReturnsError) { EXPECT_THAT( - EvaluateExpr(*EqExpr({SharedConstant(testutil::Value(1LL)), - std::make_shared("nonexistent")})), + EvaluateExpr(*EqualExpr({std::make_shared("nonexistent"), + SharedConstant(testutil::Value(1LL))})), + ReturnsError()); + EXPECT_THAT( + EvaluateExpr(*EqualExpr({SharedConstant(testutil::Value(1LL)), + std::make_shared("nonexistent")})), ReturnsError()); } -// --- Neq (!=) Tests --- +// --- NotEqual (!=) Tests --- -TEST_F(NeqFunctionTest, EquivalentValuesReturnFalse) { +TEST_F(NotEqualFunctionTest, EquivalentValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::EquivalentValues()) { - EXPECT_THAT(EvaluateExpr(*NeqExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({pair.first, pair.second})), Returns(testutil::Value(false))) - << "neq(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "not_equal(" << ExprId(pair.first) << ", " << ExprId(pair.second) + << ")"; } } -TEST_F(NeqFunctionTest, LessThanValuesReturnTrue) { +TEST_F(NotEqualFunctionTest, LessThanValuesReturnTrue) { for (const auto& pair : ComparisonValueTestData::LessThanValues()) { - EXPECT_THAT(EvaluateExpr(*NeqExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({pair.first, pair.second})), Returns(testutil::Value(true))) - << "neq(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "not_equal(" << ExprId(pair.first) << ", " << ExprId(pair.second) + << ")"; } } -TEST_F(NeqFunctionTest, GreaterThanValuesReturnTrue) { +TEST_F(NotEqualFunctionTest, GreaterThanValuesReturnTrue) { for (const auto& pair : ComparisonValueTestData::GreaterThanValues()) { - EXPECT_THAT(EvaluateExpr(*NeqExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({pair.first, pair.second})), Returns(testutil::Value(true))) - << "neq(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "not_equal(" << ExprId(pair.first) << ", " << ExprId(pair.second) + << ")"; } } -TEST_F(NeqFunctionTest, MixedTypeValuesReturnTrue) { +TEST_F(NotEqualFunctionTest, MixedTypeValuesReturnTrue) { for (const auto& pair : ComparisonValueTestData::MixedTypeValues()) { - EXPECT_THAT(EvaluateExpr(*NeqExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({pair.first, pair.second})), Returns(testutil::Value(true))) - << "neq(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "not_equal(" << ExprId(pair.first) << ", " << ExprId(pair.second) + << ")"; } } -// --- Specific Neq Tests --- +// --- Specific NotEqual Tests --- -TEST_F(NeqFunctionTest, NullNotEqualsNullReturnsNull) { - EXPECT_THAT(EvaluateExpr(*NeqExpr({SharedConstant(model::NullValue()), - SharedConstant(model::NullValue())})), +TEST_F(NotEqualFunctionTest, NullNotEqualsNullReturnsNull) { + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({SharedConstant(model::NullValue()), + SharedConstant(model::NullValue())})), ReturnsNull()); } // Corresponds to neq.null_any_returnsNull -TEST_F(NeqFunctionTest, NullOperandReturnsNull) { +TEST_F(NotEqualFunctionTest, NullOperandReturnsNull) { for (const auto& val : ComparisonValueTestData::AllSupportedComparableValues()) { EXPECT_THAT( - EvaluateExpr(*NeqExpr({SharedConstant(model::NullValue()), val})), + EvaluateExpr(*NotEqualExpr({SharedConstant(model::NullValue()), val})), ReturnsNull()) - << "neq(null, " << ExprId(val) << ")"; + << "not_equal(null, " << ExprId(val) << ")"; EXPECT_THAT( - EvaluateExpr(*NeqExpr({val, SharedConstant(model::NullValue())})), + EvaluateExpr(*NotEqualExpr({val, SharedConstant(model::NullValue())})), ReturnsNull()) - << "neq(" << ExprId(val) << ", null)"; + << "not_equal(" << ExprId(val) << ", null)"; } - EXPECT_THAT( - EvaluateExpr(*NeqExpr({SharedConstant(model::NullValue()), - std::make_shared("nonexistent")})), - ReturnsError()); + EXPECT_THAT(EvaluateExpr( + *NotEqualExpr({SharedConstant(model::NullValue()), + std::make_shared("nonexistent")})), + ReturnsError()); } // Corresponds to neq.nan tests -TEST_F(NeqFunctionTest, NaNComparisonsReturnTrue) { +TEST_F(NotEqualFunctionTest, NaNComparisonsReturnTrue) { auto nan_expr = SharedConstant(std::numeric_limits::quiet_NaN()); - EXPECT_THAT(EvaluateExpr(*NeqExpr({nan_expr, nan_expr})), + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({nan_expr, nan_expr})), Returns(testutil::Value(true))); // NaN != NaN is true for (const auto& num_val : ComparisonValueTestData::NumericValues()) { - EXPECT_THAT(EvaluateExpr(*NeqExpr({nan_expr, num_val})), + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({nan_expr, num_val})), Returns(testutil::Value(true))) - << "neq(NaN, " << ExprId(num_val) << ")"; - EXPECT_THAT(EvaluateExpr(*NeqExpr({num_val, nan_expr})), + << "not_equal(NaN, " << ExprId(num_val) << ")"; + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({num_val, nan_expr})), Returns(testutil::Value(true))) - << "neq(" << ExprId(num_val) << ", NaN)"; + << "not_equal(" << ExprId(num_val) << ", NaN)"; } for (const auto& other_val : @@ -358,23 +363,23 @@ TEST_F(NeqFunctionTest, NaNComparisonsReturnTrue) { } } if (!is_numeric) { - EXPECT_THAT(EvaluateExpr(*NeqExpr({nan_expr, other_val})), + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({nan_expr, other_val})), Returns(testutil::Value(true))) - << "neq(NaN, " << ExprId(other_val) << ")"; - EXPECT_THAT(EvaluateExpr(*NeqExpr({other_val, nan_expr})), + << "not_equal(NaN, " << ExprId(other_val) << ")"; + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({other_val, nan_expr})), Returns(testutil::Value(true))) - << "neq(" << ExprId(other_val) << ", NaN)"; + << "not_equal(" << ExprId(other_val) << ", NaN)"; } } + EXPECT_THAT(EvaluateExpr(*NotEqualExpr( + {SharedConstant(testutil::Array(testutil::Value( + std::numeric_limits::quiet_NaN()))), + SharedConstant(testutil::Array(testutil::Value( + std::numeric_limits::quiet_NaN())))})), + Returns(testutil::Value(true))); EXPECT_THAT( - EvaluateExpr(*NeqExpr({SharedConstant(testutil::Array(testutil::Value( - std::numeric_limits::quiet_NaN()))), - SharedConstant(testutil::Array(testutil::Value( - std::numeric_limits::quiet_NaN())))})), - Returns(testutil::Value(true))); - EXPECT_THAT( - EvaluateExpr(*NeqExpr( + EvaluateExpr(*NotEqualExpr( {SharedConstant(testutil::Map( "foo", testutil::Value(std::numeric_limits::quiet_NaN()))), @@ -385,110 +390,115 @@ TEST_F(NeqFunctionTest, NaNComparisonsReturnTrue) { } // Corresponds to neq.error_ tests -TEST_F(NeqFunctionTest, ErrorHandling) { +TEST_F(NotEqualFunctionTest, ErrorHandling) { auto error_expr = std::make_shared("a.b"); auto non_map_input = testutil::Doc("coll/doc", 1, testutil::Map("a", 123)); for (const auto& val : ComparisonValueTestData::AllSupportedComparableValues()) { - EXPECT_THAT(EvaluateExpr(*NeqExpr({error_expr, val}), non_map_input), + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({error_expr, val}), non_map_input), ReturnsError()); - EXPECT_THAT(EvaluateExpr(*NeqExpr({val, error_expr}), non_map_input), + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({val, error_expr}), non_map_input), ReturnsError()); } - EXPECT_THAT(EvaluateExpr(*NeqExpr({error_expr, error_expr}), non_map_input), - ReturnsError()); EXPECT_THAT( - EvaluateExpr(*NeqExpr({error_expr, SharedConstant(model::NullValue())}), - non_map_input), + EvaluateExpr(*NotEqualExpr({error_expr, error_expr}), non_map_input), ReturnsError()); + EXPECT_THAT(EvaluateExpr(*NotEqualExpr({error_expr, + SharedConstant(model::NullValue())}), + non_map_input), + ReturnsError()); } -TEST_F(NeqFunctionTest, MissingFieldReturnsError) { +TEST_F(NotEqualFunctionTest, MissingFieldReturnsError) { EXPECT_THAT( - EvaluateExpr(*NeqExpr({std::make_shared("nonexistent"), - SharedConstant(testutil::Value(1LL))})), - ReturnsError()); - EXPECT_THAT( - EvaluateExpr(*NeqExpr({SharedConstant(testutil::Value(1LL)), - std::make_shared("nonexistent")})), + EvaluateExpr(*NotEqualExpr({std::make_shared("nonexistent"), + SharedConstant(testutil::Value(1LL))})), ReturnsError()); + EXPECT_THAT(EvaluateExpr( + *NotEqualExpr({SharedConstant(testutil::Value(1LL)), + std::make_shared("nonexistent")})), + ReturnsError()); } -// --- Lt (<) Tests --- +// --- LessThan (<) Tests --- -TEST_F(LtFunctionTest, EquivalentValuesReturnFalse) { +TEST_F(LessThanFunctionTest, EquivalentValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::EquivalentValues()) { - EXPECT_THAT(EvaluateExpr(*LtExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*LessThanExpr({pair.first, pair.second})), Returns(testutil::Value(false))) - << "lt(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "less_than(" << ExprId(pair.first) << ", " << ExprId(pair.second) + << ")"; } } -TEST_F(LtFunctionTest, LessThanValuesReturnTrue) { +TEST_F(LessThanFunctionTest, LessThanValuesReturnTrue) { for (const auto& pair : ComparisonValueTestData::LessThanValues()) { auto left_const = std::dynamic_pointer_cast(pair.first); auto right_const = std::dynamic_pointer_cast(pair.second); // Use model::Equals to check for non-equal comparable pairs - EXPECT_THAT(EvaluateExpr(*LtExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*LessThanExpr({pair.first, pair.second})), Returns(testutil::Value(true))) - << "lt(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "less_than(" << ExprId(pair.first) << ", " << ExprId(pair.second) + << ")"; } } -TEST_F(LtFunctionTest, GreaterThanValuesReturnFalse) { +TEST_F(LessThanFunctionTest, GreaterThanValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::GreaterThanValues()) { - EXPECT_THAT(EvaluateExpr(*LtExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*LessThanExpr({pair.first, pair.second})), Returns(testutil::Value(false))) - << "lt(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "less_than(" << ExprId(pair.first) << ", " << ExprId(pair.second) + << ")"; } } -TEST_F(LtFunctionTest, MixedTypeValuesReturnFalse) { +TEST_F(LessThanFunctionTest, MixedTypeValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::MixedTypeValues()) { - EXPECT_THAT(EvaluateExpr(*LtExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*LessThanExpr({pair.first, pair.second})), Returns(testutil::Value(false))) - << "lt(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "less_than(" << ExprId(pair.first) << ", " << ExprId(pair.second) + << ")"; } } -// --- Specific Lt Tests --- +// --- Specific LessThan Tests --- -TEST_F(LtFunctionTest, NullOperandReturnsNull) { +TEST_F(LessThanFunctionTest, NullOperandReturnsNull) { for (const auto& val : ComparisonValueTestData::AllSupportedComparableValues()) { EXPECT_THAT( - EvaluateExpr(*LtExpr({SharedConstant(model::NullValue()), val})), + EvaluateExpr(*LessThanExpr({SharedConstant(model::NullValue()), val})), ReturnsNull()) - << "lt(null, " << ExprId(val) << ")"; + << "less_than(null, " << ExprId(val) << ")"; EXPECT_THAT( - EvaluateExpr(*LtExpr({val, SharedConstant(model::NullValue())})), + EvaluateExpr(*LessThanExpr({val, SharedConstant(model::NullValue())})), ReturnsNull()) - << "lt(" << ExprId(val) << ", null)"; + << "less_than(" << ExprId(val) << ", null)"; } - EXPECT_THAT(EvaluateExpr(*LtExpr({SharedConstant(model::NullValue()), - SharedConstant(model::NullValue())})), + EXPECT_THAT(EvaluateExpr(*LessThanExpr({SharedConstant(model::NullValue()), + SharedConstant(model::NullValue())})), ReturnsNull()); - EXPECT_THAT( - EvaluateExpr(*LtExpr({SharedConstant(model::NullValue()), - std::make_shared("nonexistent")})), - ReturnsError()); + EXPECT_THAT(EvaluateExpr( + *LessThanExpr({SharedConstant(model::NullValue()), + std::make_shared("nonexistent")})), + ReturnsError()); } -TEST_F(LtFunctionTest, NaNComparisonsReturnFalse) { +TEST_F(LessThanFunctionTest, NaNComparisonsReturnFalse) { auto nan_expr = SharedConstant(std::numeric_limits::quiet_NaN()); - EXPECT_THAT(EvaluateExpr(*LtExpr({nan_expr, nan_expr})), + EXPECT_THAT(EvaluateExpr(*LessThanExpr({nan_expr, nan_expr})), Returns(testutil::Value(false))); for (const auto& num_val : ComparisonValueTestData::NumericValues()) { - EXPECT_THAT(EvaluateExpr(*LtExpr({nan_expr, num_val})), + EXPECT_THAT(EvaluateExpr(*LessThanExpr({nan_expr, num_val})), Returns(testutil::Value(false))) - << "lt(NaN, " << ExprId(num_val) << ")"; - EXPECT_THAT(EvaluateExpr(*LtExpr({num_val, nan_expr})), + << "less_than(NaN, " << ExprId(num_val) << ")"; + EXPECT_THAT(EvaluateExpr(*LessThanExpr({num_val, nan_expr})), Returns(testutil::Value(false))) - << "lt(" << ExprId(num_val) << ", NaN)"; + << "less_than(" << ExprId(num_val) << ", NaN)"; } for (const auto& other_val : ComparisonValueTestData::AllSupportedComparableValues()) { @@ -500,120 +510,127 @@ TEST_F(LtFunctionTest, NaNComparisonsReturnFalse) { } } if (!is_numeric) { - EXPECT_THAT(EvaluateExpr(*LtExpr({nan_expr, other_val})), + EXPECT_THAT(EvaluateExpr(*LessThanExpr({nan_expr, other_val})), Returns(testutil::Value(false))) - << "lt(NaN, " << ExprId(other_val) << ")"; - EXPECT_THAT(EvaluateExpr(*LtExpr({other_val, nan_expr})), + << "less_than(NaN, " << ExprId(other_val) << ")"; + EXPECT_THAT(EvaluateExpr(*LessThanExpr({other_val, nan_expr})), Returns(testutil::Value(false))) - << "lt(" << ExprId(other_val) << ", NaN)"; + << "less_than(" << ExprId(other_val) << ", NaN)"; } } - EXPECT_THAT( - EvaluateExpr(*LtExpr({SharedConstant(testutil::Array(testutil::Value( - std::numeric_limits::quiet_NaN()))), - SharedConstant(testutil::Array(testutil::Value( - std::numeric_limits::quiet_NaN())))})), - Returns(testutil::Value(false))); + EXPECT_THAT(EvaluateExpr(*LessThanExpr( + {SharedConstant(testutil::Array(testutil::Value( + std::numeric_limits::quiet_NaN()))), + SharedConstant(testutil::Array(testutil::Value( + std::numeric_limits::quiet_NaN())))})), + Returns(testutil::Value(false))); } -TEST_F(LtFunctionTest, ErrorHandling) { +TEST_F(LessThanFunctionTest, ErrorHandling) { auto error_expr = std::make_shared("a.b"); auto non_map_input = testutil::Doc("coll/doc", 1, testutil::Map("a", 123)); for (const auto& val : ComparisonValueTestData::AllSupportedComparableValues()) { - EXPECT_THAT(EvaluateExpr(*LtExpr({error_expr, val}), non_map_input), + EXPECT_THAT(EvaluateExpr(*LessThanExpr({error_expr, val}), non_map_input), ReturnsError()); - EXPECT_THAT(EvaluateExpr(*LtExpr({val, error_expr}), non_map_input), + EXPECT_THAT(EvaluateExpr(*LessThanExpr({val, error_expr}), non_map_input), ReturnsError()); } - EXPECT_THAT(EvaluateExpr(*LtExpr({error_expr, error_expr}), non_map_input), - ReturnsError()); EXPECT_THAT( - EvaluateExpr(*LtExpr({error_expr, SharedConstant(model::NullValue())}), - non_map_input), + EvaluateExpr(*LessThanExpr({error_expr, error_expr}), non_map_input), ReturnsError()); + EXPECT_THAT(EvaluateExpr(*LessThanExpr({error_expr, + SharedConstant(model::NullValue())}), + non_map_input), + ReturnsError()); } -TEST_F(LtFunctionTest, MissingFieldReturnsError) { - EXPECT_THAT(EvaluateExpr(*LtExpr({std::make_shared("nonexistent"), - SharedConstant(testutil::Value(1LL))})), - ReturnsError()); +TEST_F(LessThanFunctionTest, MissingFieldReturnsError) { EXPECT_THAT( - EvaluateExpr(*LtExpr({SharedConstant(testutil::Value(1LL)), - std::make_shared("nonexistent")})), + EvaluateExpr(*LessThanExpr({std::make_shared("nonexistent"), + SharedConstant(testutil::Value(1LL))})), ReturnsError()); + EXPECT_THAT(EvaluateExpr( + *LessThanExpr({SharedConstant(testutil::Value(1LL)), + std::make_shared("nonexistent")})), + ReturnsError()); } -// --- Lte (<=) Tests --- +// --- LessThanOrEqual (<=) Tests --- -TEST_F(LteFunctionTest, EquivalentValuesReturnTrue) { +TEST_F(LessThanOrEqualFunctionTest, EquivalentValuesReturnTrue) { for (const auto& pair : ComparisonValueTestData::EquivalentValues()) { - EXPECT_THAT(EvaluateExpr(*LteExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr({pair.first, pair.second})), Returns(testutil::Value(true))) - << "lte(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "less_than_or_equal(" << ExprId(pair.first) << ", " + << ExprId(pair.second) << ")"; } } -TEST_F(LteFunctionTest, LessThanValuesReturnTrue) { +TEST_F(LessThanOrEqualFunctionTest, LessThanValuesReturnTrue) { for (const auto& pair : ComparisonValueTestData::LessThanValues()) { - EXPECT_THAT(EvaluateExpr(*LteExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr({pair.first, pair.second})), Returns(testutil::Value(true))) - << "lte(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "less_than_or_equal(" << ExprId(pair.first) << ", " + << ExprId(pair.second) << ")"; } } -TEST_F(LteFunctionTest, GreaterThanValuesReturnFalse) { +TEST_F(LessThanOrEqualFunctionTest, GreaterThanValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::GreaterThanValues()) { - EXPECT_THAT(EvaluateExpr(*LteExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr({pair.first, pair.second})), Returns(testutil::Value(false))) - << "lte(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "less_than_or_equal(" << ExprId(pair.first) << ", " + << ExprId(pair.second) << ")"; } } -TEST_F(LteFunctionTest, MixedTypeValuesReturnFalse) { +TEST_F(LessThanOrEqualFunctionTest, MixedTypeValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::MixedTypeValues()) { - EXPECT_THAT(EvaluateExpr(*LteExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr({pair.first, pair.second})), Returns(testutil::Value(false))) - << "lte(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "less_than_or_equal(" << ExprId(pair.first) << ", " + << ExprId(pair.second) << ")"; } } -// --- Specific Lte Tests --- +// --- Specific LessThanOrEqual Tests --- -TEST_F(LteFunctionTest, NullOperandReturnsNull) { +TEST_F(LessThanOrEqualFunctionTest, NullOperandReturnsNull) { for (const auto& val : ComparisonValueTestData::AllSupportedComparableValues()) { - EXPECT_THAT( - EvaluateExpr(*LteExpr({SharedConstant(model::NullValue()), val})), - ReturnsNull()) - << "lte(null, " << ExprId(val) << ")"; - EXPECT_THAT( - EvaluateExpr(*LteExpr({val, SharedConstant(model::NullValue())})), - ReturnsNull()) - << "lte(" << ExprId(val) << ", null)"; - } - EXPECT_THAT(EvaluateExpr(*LteExpr({SharedConstant(model::NullValue()), - SharedConstant(model::NullValue())})), - ReturnsNull()); - EXPECT_THAT( - EvaluateExpr(*LteExpr({SharedConstant(model::NullValue()), - std::make_shared("nonexistent")})), - ReturnsError()); + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr( + {SharedConstant(model::NullValue()), val})), + ReturnsNull()) + << "less_than_or_equal(null, " << ExprId(val) << ")"; + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr( + {val, SharedConstant(model::NullValue())})), + ReturnsNull()) + << "less_than_or_equal(" << ExprId(val) << ", null)"; + } + EXPECT_THAT( + EvaluateExpr(*LessThanOrEqualExpr({SharedConstant(model::NullValue()), + SharedConstant(model::NullValue())})), + ReturnsNull()); + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr( + {SharedConstant(model::NullValue()), + std::make_shared("nonexistent")})), + ReturnsError()); } -TEST_F(LteFunctionTest, NaNComparisonsReturnFalse) { +TEST_F(LessThanOrEqualFunctionTest, NaNComparisonsReturnFalse) { auto nan_expr = SharedConstant(std::numeric_limits::quiet_NaN()); - EXPECT_THAT(EvaluateExpr(*LteExpr({nan_expr, nan_expr})), + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr({nan_expr, nan_expr})), Returns(testutil::Value(false))); for (const auto& num_val : ComparisonValueTestData::NumericValues()) { - EXPECT_THAT(EvaluateExpr(*LteExpr({nan_expr, num_val})), + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr({nan_expr, num_val})), Returns(testutil::Value(false))) - << "lte(NaN, " << ExprId(num_val) << ")"; - EXPECT_THAT(EvaluateExpr(*LteExpr({num_val, nan_expr})), + << "less_than_or_equal(NaN, " << ExprId(num_val) << ")"; + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr({num_val, nan_expr})), Returns(testutil::Value(false))) - << "lte(" << ExprId(num_val) << ", NaN)"; + << "less_than_or_equal(" << ExprId(num_val) << ", NaN)"; } for (const auto& other_val : ComparisonValueTestData::AllSupportedComparableValues()) { @@ -625,71 +642,77 @@ TEST_F(LteFunctionTest, NaNComparisonsReturnFalse) { } } if (!is_numeric) { - EXPECT_THAT(EvaluateExpr(*LteExpr({nan_expr, other_val})), + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr({nan_expr, other_val})), Returns(testutil::Value(false))) - << "lte(NaN, " << ExprId(other_val) << ")"; - EXPECT_THAT(EvaluateExpr(*LteExpr({other_val, nan_expr})), + << "less_than_or_equal(NaN, " << ExprId(other_val) << ")"; + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr({other_val, nan_expr})), Returns(testutil::Value(false))) - << "lte(" << ExprId(other_val) << ", NaN)"; + << "less_than_or_equal(" << ExprId(other_val) << ", NaN)"; } } - EXPECT_THAT( - EvaluateExpr(*LteExpr({SharedConstant(testutil::Array(testutil::Value( - std::numeric_limits::quiet_NaN()))), - SharedConstant(testutil::Array(testutil::Value( - std::numeric_limits::quiet_NaN())))})), - Returns(testutil::Value(false))); + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr( + {SharedConstant(testutil::Array(testutil::Value( + std::numeric_limits::quiet_NaN()))), + SharedConstant(testutil::Array(testutil::Value( + std::numeric_limits::quiet_NaN())))})), + Returns(testutil::Value(false))); } -TEST_F(LteFunctionTest, ErrorHandling) { +TEST_F(LessThanOrEqualFunctionTest, ErrorHandling) { auto error_expr = std::make_shared("a.b"); auto non_map_input = testutil::Doc("coll/doc", 1, testutil::Map("a", 123)); for (const auto& val : ComparisonValueTestData::AllSupportedComparableValues()) { - EXPECT_THAT(EvaluateExpr(*LteExpr({error_expr, val}), non_map_input), - ReturnsError()); - EXPECT_THAT(EvaluateExpr(*LteExpr({val, error_expr}), non_map_input), - ReturnsError()); + EXPECT_THAT( + EvaluateExpr(*LessThanOrEqualExpr({error_expr, val}), non_map_input), + ReturnsError()); + EXPECT_THAT( + EvaluateExpr(*LessThanOrEqualExpr({val, error_expr}), non_map_input), + ReturnsError()); } - EXPECT_THAT(EvaluateExpr(*LteExpr({error_expr, error_expr}), non_map_input), + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr({error_expr, error_expr}), + non_map_input), ReturnsError()); EXPECT_THAT( - EvaluateExpr(*LteExpr({error_expr, SharedConstant(model::NullValue())}), + EvaluateExpr(*LessThanOrEqualExpr( + {error_expr, SharedConstant(model::NullValue())}), non_map_input), ReturnsError()); } -TEST_F(LteFunctionTest, MissingFieldReturnsError) { - EXPECT_THAT( - EvaluateExpr(*LteExpr({std::make_shared("nonexistent"), - SharedConstant(testutil::Value(1LL))})), - ReturnsError()); - EXPECT_THAT( - EvaluateExpr(*LteExpr({SharedConstant(testutil::Value(1LL)), - std::make_shared("nonexistent")})), - ReturnsError()); +TEST_F(LessThanOrEqualFunctionTest, MissingFieldReturnsError) { + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr( + {std::make_shared("nonexistent"), + SharedConstant(testutil::Value(1LL))})), + ReturnsError()); + EXPECT_THAT(EvaluateExpr(*LessThanOrEqualExpr( + {SharedConstant(testutil::Value(1LL)), + std::make_shared("nonexistent")})), + ReturnsError()); } -// --- Gt (>) Tests --- +// --- GreaterThan (>) Tests --- -TEST_F(GtFunctionTest, EquivalentValuesReturnFalse) { +TEST_F(GreaterThanFunctionTest, EquivalentValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::EquivalentValues()) { - EXPECT_THAT(EvaluateExpr(*GtExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr({pair.first, pair.second})), Returns(testutil::Value(false))) - << "gt(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "greater_than(" << ExprId(pair.first) << ", " << ExprId(pair.second) + << ")"; } } -TEST_F(GtFunctionTest, LessThanValuesReturnFalse) { +TEST_F(GreaterThanFunctionTest, LessThanValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::LessThanValues()) { - EXPECT_THAT(EvaluateExpr(*GtExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr({pair.first, pair.second})), Returns(testutil::Value(false))) - << "gt(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "greater_than(" << ExprId(pair.first) << ", " << ExprId(pair.second) + << ")"; } } -TEST_F(GtFunctionTest, GreaterThanValuesReturnTrue) { +TEST_F(GreaterThanFunctionTest, GreaterThanValuesReturnTrue) { for (const auto& pair : ComparisonValueTestData::GreaterThanValues()) { // This set includes pairs like {1.0, 1} which compare as !GreaterThan. // We expect false for those, true otherwise. @@ -697,55 +720,58 @@ TEST_F(GtFunctionTest, GreaterThanValuesReturnTrue) { std::dynamic_pointer_cast(pair.first); auto right_const = std::dynamic_pointer_cast(pair.second); - EXPECT_THAT(EvaluateExpr(*GtExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr({pair.first, pair.second})), Returns(testutil::Value(true))) - << "gt(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "greater_than(" << ExprId(pair.first) << ", " << ExprId(pair.second) + << ")"; } } -TEST_F(GtFunctionTest, MixedTypeValuesReturnFalse) { +TEST_F(GreaterThanFunctionTest, MixedTypeValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::MixedTypeValues()) { - EXPECT_THAT(EvaluateExpr(*GtExpr({pair.first, pair.second})), + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr({pair.first, pair.second})), Returns(testutil::Value(false))) - << "gt(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + << "greater_than(" << ExprId(pair.first) << ", " << ExprId(pair.second) + << ")"; } } -// --- Specific Gt Tests --- +// --- Specific GreaterThan Tests --- -TEST_F(GtFunctionTest, NullOperandReturnsNull) { +TEST_F(GreaterThanFunctionTest, NullOperandReturnsNull) { for (const auto& val : ComparisonValueTestData::AllSupportedComparableValues()) { - EXPECT_THAT( - EvaluateExpr(*GtExpr({SharedConstant(model::NullValue()), val})), - ReturnsNull()) - << "gt(null, " << ExprId(val) << ")"; - EXPECT_THAT( - EvaluateExpr(*GtExpr({val, SharedConstant(model::NullValue())})), - ReturnsNull()) - << "gt(" << ExprId(val) << ", null)"; + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr( + {SharedConstant(model::NullValue()), val})), + ReturnsNull()) + << "greater_than(null, " << ExprId(val) << ")"; + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr( + {val, SharedConstant(model::NullValue())})), + ReturnsNull()) + << "greater_than(" << ExprId(val) << ", null)"; } - EXPECT_THAT(EvaluateExpr(*GtExpr({SharedConstant(model::NullValue()), - SharedConstant(model::NullValue())})), - ReturnsNull()); EXPECT_THAT( - EvaluateExpr(*GtExpr({SharedConstant(model::NullValue()), - std::make_shared("nonexistent")})), - ReturnsError()); + EvaluateExpr(*GreaterThanExpr({SharedConstant(model::NullValue()), + SharedConstant(model::NullValue())})), + ReturnsNull()); + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr( + {SharedConstant(model::NullValue()), + std::make_shared("nonexistent")})), + ReturnsError()); } -TEST_F(GtFunctionTest, NaNComparisonsReturnFalse) { +TEST_F(GreaterThanFunctionTest, NaNComparisonsReturnFalse) { auto nan_expr = SharedConstant(std::numeric_limits::quiet_NaN()); - EXPECT_THAT(EvaluateExpr(*GtExpr({nan_expr, nan_expr})), + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr({nan_expr, nan_expr})), Returns(testutil::Value(false))); for (const auto& num_val : ComparisonValueTestData::NumericValues()) { - EXPECT_THAT(EvaluateExpr(*GtExpr({nan_expr, num_val})), + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr({nan_expr, num_val})), Returns(testutil::Value(false))) - << "gt(NaN, " << ExprId(num_val) << ")"; - EXPECT_THAT(EvaluateExpr(*GtExpr({num_val, nan_expr})), + << "greater_than(NaN, " << ExprId(num_val) << ")"; + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr({num_val, nan_expr})), Returns(testutil::Value(false))) - << "gt(" << ExprId(num_val) << ", NaN)"; + << "greater_than(" << ExprId(num_val) << ", NaN)"; } for (const auto& other_val : ComparisonValueTestData::AllSupportedComparableValues()) { @@ -757,120 +783,134 @@ TEST_F(GtFunctionTest, NaNComparisonsReturnFalse) { } } if (!is_numeric) { - EXPECT_THAT(EvaluateExpr(*GtExpr({nan_expr, other_val})), + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr({nan_expr, other_val})), Returns(testutil::Value(false))) - << "gt(NaN, " << ExprId(other_val) << ")"; - EXPECT_THAT(EvaluateExpr(*GtExpr({other_val, nan_expr})), + << "greater_than(NaN, " << ExprId(other_val) << ")"; + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr({other_val, nan_expr})), Returns(testutil::Value(false))) - << "gt(" << ExprId(other_val) << ", NaN)"; + << "greater_than(" << ExprId(other_val) << ", NaN)"; } } - EXPECT_THAT( - EvaluateExpr(*GtExpr({SharedConstant(testutil::Array(testutil::Value( - std::numeric_limits::quiet_NaN()))), - SharedConstant(testutil::Array(testutil::Value( - std::numeric_limits::quiet_NaN())))})), - Returns(testutil::Value(false))); + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr( + {SharedConstant(testutil::Array(testutil::Value( + std::numeric_limits::quiet_NaN()))), + SharedConstant(testutil::Array(testutil::Value( + std::numeric_limits::quiet_NaN())))})), + Returns(testutil::Value(false))); } -TEST_F(GtFunctionTest, ErrorHandling) { +TEST_F(GreaterThanFunctionTest, ErrorHandling) { auto error_expr = std::make_shared("a.b"); auto non_map_input = testutil::Doc("coll/doc", 1, testutil::Map("a", 123)); for (const auto& val : ComparisonValueTestData::AllSupportedComparableValues()) { - EXPECT_THAT(EvaluateExpr(*GtExpr({error_expr, val}), non_map_input), - ReturnsError()); - EXPECT_THAT(EvaluateExpr(*GtExpr({val, error_expr}), non_map_input), - ReturnsError()); + EXPECT_THAT( + EvaluateExpr(*GreaterThanExpr({error_expr, val}), non_map_input), + ReturnsError()); + EXPECT_THAT( + EvaluateExpr(*GreaterThanExpr({val, error_expr}), non_map_input), + ReturnsError()); } - EXPECT_THAT(EvaluateExpr(*GtExpr({error_expr, error_expr}), non_map_input), - ReturnsError()); EXPECT_THAT( - EvaluateExpr(*GtExpr({error_expr, SharedConstant(model::NullValue())}), - non_map_input), + EvaluateExpr(*GreaterThanExpr({error_expr, error_expr}), non_map_input), + ReturnsError()); + EXPECT_THAT( + EvaluateExpr( + *GreaterThanExpr({error_expr, SharedConstant(model::NullValue())}), + non_map_input), ReturnsError()); } -TEST_F(GtFunctionTest, MissingFieldReturnsError) { - EXPECT_THAT(EvaluateExpr(*GtExpr({std::make_shared("nonexistent"), +TEST_F(GreaterThanFunctionTest, MissingFieldReturnsError) { + EXPECT_THAT(EvaluateExpr( + *GreaterThanExpr({std::make_shared("nonexistent"), SharedConstant(testutil::Value(1LL))})), ReturnsError()); - EXPECT_THAT( - EvaluateExpr(*GtExpr({SharedConstant(testutil::Value(1LL)), - std::make_shared("nonexistent")})), - ReturnsError()); + EXPECT_THAT(EvaluateExpr(*GreaterThanExpr( + {SharedConstant(testutil::Value(1LL)), + std::make_shared("nonexistent")})), + ReturnsError()); } -// --- Gte (>=) Tests --- +// --- GreaterThanOrEqual (>=) Tests --- -TEST_F(GteFunctionTest, EquivalentValuesReturnTrue) { +TEST_F(GreaterThanOrEqualFunctionTest, EquivalentValuesReturnTrue) { for (const auto& pair : ComparisonValueTestData::EquivalentValues()) { - EXPECT_THAT(EvaluateExpr(*GteExpr({pair.first, pair.second})), - Returns(testutil::Value(true))) - << "gte(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + EXPECT_THAT( + EvaluateExpr(*GreaterThanOrEqualExpr({pair.first, pair.second})), + Returns(testutil::Value(true))) + << "greater_than_or_equal(" << ExprId(pair.first) << ", " + << ExprId(pair.second) << ")"; } } -TEST_F(GteFunctionTest, LessThanValuesReturnFalse) { +TEST_F(GreaterThanOrEqualFunctionTest, LessThanValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::LessThanValues()) { - EXPECT_THAT(EvaluateExpr(*GteExpr({pair.first, pair.second})), - Returns(testutil::Value(false))) - << "gte(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + EXPECT_THAT( + EvaluateExpr(*GreaterThanOrEqualExpr({pair.first, pair.second})), + Returns(testutil::Value(false))) + << "greater_than_or_equal(" << ExprId(pair.first) << ", " + << ExprId(pair.second) << ")"; } } -TEST_F(GteFunctionTest, GreaterThanValuesReturnTrue) { +TEST_F(GreaterThanOrEqualFunctionTest, GreaterThanValuesReturnTrue) { for (const auto& pair : ComparisonValueTestData::GreaterThanValues()) { - EXPECT_THAT(EvaluateExpr(*GteExpr({pair.first, pair.second})), - Returns(testutil::Value(true))) - << "gte(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + EXPECT_THAT( + EvaluateExpr(*GreaterThanOrEqualExpr({pair.first, pair.second})), + Returns(testutil::Value(true))) + << "greater_than_or_equal(" << ExprId(pair.first) << ", " + << ExprId(pair.second) << ")"; } } -TEST_F(GteFunctionTest, MixedTypeValuesReturnFalse) { +TEST_F(GreaterThanOrEqualFunctionTest, MixedTypeValuesReturnFalse) { for (const auto& pair : ComparisonValueTestData::MixedTypeValues()) { - EXPECT_THAT(EvaluateExpr(*GteExpr({pair.first, pair.second})), - Returns(testutil::Value(false))) - << "gte(" << ExprId(pair.first) << ", " << ExprId(pair.second) << ")"; + EXPECT_THAT( + EvaluateExpr(*GreaterThanOrEqualExpr({pair.first, pair.second})), + Returns(testutil::Value(false))) + << "greater_than_or_equal(" << ExprId(pair.first) << ", " + << ExprId(pair.second) << ")"; } } -// --- Specific Gte Tests --- +// --- Specific GreaterThanOrEqual Tests --- -TEST_F(GteFunctionTest, NullOperandReturnsNull) { +TEST_F(GreaterThanOrEqualFunctionTest, NullOperandReturnsNull) { for (const auto& val : ComparisonValueTestData::AllSupportedComparableValues()) { - EXPECT_THAT( - EvaluateExpr(*GteExpr({SharedConstant(model::NullValue()), val})), - ReturnsNull()) - << "gte(null, " << ExprId(val) << ")"; - EXPECT_THAT( - EvaluateExpr(*GteExpr({val, SharedConstant(model::NullValue())})), - ReturnsNull()) - << "gte(" << ExprId(val) << ", null)"; - } - EXPECT_THAT(EvaluateExpr(*GteExpr({SharedConstant(model::NullValue()), - SharedConstant(model::NullValue())})), + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr( + {SharedConstant(model::NullValue()), val})), + ReturnsNull()) + << "greater_than_or_equal(null, " << ExprId(val) << ")"; + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr( + {val, SharedConstant(model::NullValue())})), + ReturnsNull()) + << "greater_than_or_equal(" << ExprId(val) << ", null)"; + } + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr( + {SharedConstant(model::NullValue()), + SharedConstant(model::NullValue())})), ReturnsNull()); - EXPECT_THAT( - EvaluateExpr(*GteExpr({SharedConstant(model::NullValue()), - std::make_shared("nonexistent")})), - ReturnsError()); + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr( + {SharedConstant(model::NullValue()), + std::make_shared("nonexistent")})), + ReturnsError()); } -TEST_F(GteFunctionTest, NaNComparisonsReturnFalse) { +TEST_F(GreaterThanOrEqualFunctionTest, NaNComparisonsReturnFalse) { auto nan_expr = SharedConstant(std::numeric_limits::quiet_NaN()); - EXPECT_THAT(EvaluateExpr(*GteExpr({nan_expr, nan_expr})), + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr({nan_expr, nan_expr})), Returns(testutil::Value(false))); for (const auto& num_val : ComparisonValueTestData::NumericValues()) { - EXPECT_THAT(EvaluateExpr(*GteExpr({nan_expr, num_val})), + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr({nan_expr, num_val})), Returns(testutil::Value(false))) - << "gte(NaN, " << ExprId(num_val) << ")"; - EXPECT_THAT(EvaluateExpr(*GteExpr({num_val, nan_expr})), + << "greater_than_or_equal(NaN, " << ExprId(num_val) << ")"; + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr({num_val, nan_expr})), Returns(testutil::Value(false))) - << "gte(" << ExprId(num_val) << ", NaN)"; + << "greater_than_or_equal(" << ExprId(num_val) << ", NaN)"; } for (const auto& other_val : ComparisonValueTestData::AllSupportedComparableValues()) { @@ -882,50 +922,54 @@ TEST_F(GteFunctionTest, NaNComparisonsReturnFalse) { } } if (!is_numeric) { - EXPECT_THAT(EvaluateExpr(*GteExpr({nan_expr, other_val})), + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr({nan_expr, other_val})), Returns(testutil::Value(false))) - << "gte(NaN, " << ExprId(other_val) << ")"; - EXPECT_THAT(EvaluateExpr(*GteExpr({other_val, nan_expr})), + << "greater_than_or_equal(NaN, " << ExprId(other_val) << ")"; + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr({other_val, nan_expr})), Returns(testutil::Value(false))) - << "gte(" << ExprId(other_val) << ", NaN)"; + << "greater_than_or_equal(" << ExprId(other_val) << ", NaN)"; } } - EXPECT_THAT( - EvaluateExpr(*GteExpr({SharedConstant(testutil::Array(testutil::Value( - std::numeric_limits::quiet_NaN()))), - SharedConstant(testutil::Array(testutil::Value( - std::numeric_limits::quiet_NaN())))})), - Returns(testutil::Value(false))); + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr( + {SharedConstant(testutil::Array(testutil::Value( + std::numeric_limits::quiet_NaN()))), + SharedConstant(testutil::Array(testutil::Value( + std::numeric_limits::quiet_NaN())))})), + Returns(testutil::Value(false))); } -TEST_F(GteFunctionTest, ErrorHandling) { +TEST_F(GreaterThanOrEqualFunctionTest, ErrorHandling) { auto error_expr = std::make_shared("a.b"); auto non_map_input = testutil::Doc("coll/doc", 1, testutil::Map("a", 123)); for (const auto& val : ComparisonValueTestData::AllSupportedComparableValues()) { - EXPECT_THAT(EvaluateExpr(*GteExpr({error_expr, val}), non_map_input), - ReturnsError()); - EXPECT_THAT(EvaluateExpr(*GteExpr({val, error_expr}), non_map_input), - ReturnsError()); + EXPECT_THAT( + EvaluateExpr(*GreaterThanOrEqualExpr({error_expr, val}), non_map_input), + ReturnsError()); + EXPECT_THAT( + EvaluateExpr(*GreaterThanOrEqualExpr({val, error_expr}), non_map_input), + ReturnsError()); } - EXPECT_THAT(EvaluateExpr(*GteExpr({error_expr, error_expr}), non_map_input), + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr({error_expr, error_expr}), + non_map_input), ReturnsError()); EXPECT_THAT( - EvaluateExpr(*GteExpr({error_expr, SharedConstant(model::NullValue())}), + EvaluateExpr(*GreaterThanOrEqualExpr( + {error_expr, SharedConstant(model::NullValue())}), non_map_input), ReturnsError()); } -TEST_F(GteFunctionTest, MissingFieldReturnsError) { - EXPECT_THAT( - EvaluateExpr(*GteExpr({std::make_shared("nonexistent"), - SharedConstant(testutil::Value(1LL))})), - ReturnsError()); - EXPECT_THAT( - EvaluateExpr(*GteExpr({SharedConstant(testutil::Value(1LL)), - std::make_shared("nonexistent")})), - ReturnsError()); +TEST_F(GreaterThanOrEqualFunctionTest, MissingFieldReturnsError) { + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr( + {std::make_shared("nonexistent"), + SharedConstant(testutil::Value(1LL))})), + ReturnsError()); + EXPECT_THAT(EvaluateExpr(*GreaterThanOrEqualExpr( + {SharedConstant(testutil::Value(1LL)), + std::make_shared("nonexistent")})), + ReturnsError()); } } // namespace core diff --git a/Firestore/core/test/unit/core/expressions/logical_test.cc b/Firestore/core/test/unit/core/expressions/logical_test.cc index 81633e2c106..73f3d10c4d9 100644 --- a/Firestore/core/test/unit/core/expressions/logical_test.cc +++ b/Firestore/core/test/unit/core/expressions/logical_test.cc @@ -50,9 +50,9 @@ using testutil::IsNanExpr; using testutil::IsNotNanExpr; using testutil::IsNotNullExpr; using testutil::IsNullExpr; -using testutil::LogicalMaxExpr; -using testutil::LogicalMinExpr; using testutil::Map; +using testutil::MaximumExpr; +using testutil::MinimumExpr; using testutil::NotExpr; using testutil::OrExpr; using testutil::Returns; @@ -507,143 +507,141 @@ TEST_F(IsNanFunctionTest, NonNumericReturnsError) { ReturnsError()); } -// --- LogicalMaximum Tests --- -class LogicalMaximumFunctionTest : public LogicalExpressionsTest {}; +// --- Maximum Tests --- +class MaximumFunctionTest : public LogicalExpressionsTest {}; -TEST_F(LogicalMaximumFunctionTest, NumericType) { - auto expr = testutil::LogicalMaxExpr( +TEST_F(MaximumFunctionTest, NumericType) { + auto expr = testutil::MaximumExpr( {SharedConstant(Value(1LL)), - testutil::LogicalMaxExpr( + testutil::MaximumExpr( {SharedConstant(Value(2.0)), SharedConstant(Value(3LL))})}); EXPECT_THAT(EvaluateExpr(*expr), Returns(Value(3LL))); // Max(1, Max(2.0, 3)) -> 3 } -TEST_F(LogicalMaximumFunctionTest, StringType) { - auto expr = testutil::LogicalMaxExpr( - {testutil::LogicalMaxExpr( +TEST_F(MaximumFunctionTest, StringType) { + auto expr = testutil::MaximumExpr( + {testutil::MaximumExpr( {SharedConstant(Value("a")), SharedConstant(Value("b"))}), SharedConstant(Value("c"))}); EXPECT_THAT(EvaluateExpr(*expr), Returns(Value("c"))); // Max(Max("a", "b"), "c") -> "c" } -TEST_F(LogicalMaximumFunctionTest, MixedType) { +TEST_F(MaximumFunctionTest, MixedType) { // Type order: Null < Bool < Number < Timestamp < String < Blob < Ref < // GeoPoint < Array < Map - auto expr = testutil::LogicalMaxExpr( + auto expr = testutil::MaximumExpr( {SharedConstant(Value(1LL)), - testutil::LogicalMaxExpr( + testutil::MaximumExpr( {SharedConstant(Value("1")), SharedConstant(Value(0LL))})}); EXPECT_THAT( EvaluateExpr(*expr), Returns(Value("1"))); // Max(1, Max("1", 0)) -> "1" (String > Number) } -TEST_F(LogicalMaximumFunctionTest, OnlyNullAndErrorReturnsNull) { - auto expr = testutil::LogicalMaxExpr({NullExpr, ErrorExpr()}); +TEST_F(MaximumFunctionTest, OnlyNullAndErrorReturnsNull) { + auto expr = testutil::MaximumExpr({NullExpr, ErrorExpr()}); EXPECT_THAT(EvaluateExpr(*expr, error_doc_), ReturnsNull()); } -TEST_F(LogicalMaximumFunctionTest, NanAndNumbers) { +TEST_F(MaximumFunctionTest, NanAndNumbers) { // NaN is handled specially; it's skipped unless it's the only non-null/error // value. - auto expr = testutil::LogicalMaxExpr({NanExpr, SharedConstant(Value(0LL))}); + auto expr = testutil::MaximumExpr({NanExpr, SharedConstant(Value(0LL))}); EXPECT_THAT(EvaluateExpr(*expr), Returns(Value(0LL))); // Max(NaN, 0) -> 0 - auto expr2 = testutil::LogicalMaxExpr({SharedConstant(Value(0LL)), NanExpr}); + auto expr2 = testutil::MaximumExpr({SharedConstant(Value(0LL)), NanExpr}); EXPECT_THAT(EvaluateExpr(*expr2), Returns(Value(0LL))); // Max(0, NaN) -> 0 - auto expr3 = testutil::LogicalMaxExpr({NanExpr, NullExpr, ErrorExpr()}); + auto expr3 = testutil::MaximumExpr({NanExpr, NullExpr, ErrorExpr()}); EXPECT_THAT(EvaluateExpr(*expr3, error_doc_), Returns(Value(NAN))); // Max(NaN, Null, Error) -> NaN - auto expr4 = testutil::LogicalMaxExpr({NanExpr, ErrorExpr()}); + auto expr4 = testutil::MaximumExpr({NanExpr, ErrorExpr()}); EXPECT_THAT(EvaluateExpr(*expr4, error_doc_), Returns(Value(NAN))); // Max(NaN, Error) -> NaN } -TEST_F(LogicalMaximumFunctionTest, ErrorInputSkip) { - auto expr = - testutil::LogicalMaxExpr({ErrorExpr(), SharedConstant(Value(1LL))}); +TEST_F(MaximumFunctionTest, ErrorInputSkip) { + auto expr = testutil::MaximumExpr({ErrorExpr(), SharedConstant(Value(1LL))}); EXPECT_THAT(EvaluateExpr(*expr, error_doc_), Returns(Value(1LL))); } -TEST_F(LogicalMaximumFunctionTest, NullInputSkip) { - auto expr = testutil::LogicalMaxExpr({NullExpr, SharedConstant(Value(1LL))}); +TEST_F(MaximumFunctionTest, NullInputSkip) { + auto expr = testutil::MaximumExpr({NullExpr, SharedConstant(Value(1LL))}); EXPECT_THAT(EvaluateExpr(*expr), Returns(Value(1LL))); } -TEST_F(LogicalMaximumFunctionTest, EquivalentNumerics) { - auto expr = testutil::LogicalMaxExpr( +TEST_F(MaximumFunctionTest, EquivalentNumerics) { + auto expr = testutil::MaximumExpr( {SharedConstant(Value(1LL)), SharedConstant(Value(1.0))}); // Max(1, 1.0) -> 1 (or 1.0, they are equivalent, result depends on internal // order) Let's check if it's equivalent to 1LL EXPECT_THAT(EvaluateExpr(*expr), Returns(Value(1LL))); } -// --- LogicalMinimum Tests --- -class LogicalMinimumFunctionTest : public LogicalExpressionsTest {}; +// --- Minimum Tests --- +class MinimumFunctionTest : public LogicalExpressionsTest {}; -TEST_F(LogicalMinimumFunctionTest, NumericType) { - auto expr = testutil::LogicalMinExpr( +TEST_F(MinimumFunctionTest, NumericType) { + auto expr = testutil::MinimumExpr( {SharedConstant(Value(1LL)), - testutil::LogicalMinExpr( + testutil::MinimumExpr( {SharedConstant(Value(2.0)), SharedConstant(Value(3LL))})}); EXPECT_THAT(EvaluateExpr(*expr), Returns(Value(1LL))); // Min(1, Min(2.0, 3)) -> 1 } -TEST_F(LogicalMinimumFunctionTest, StringType) { - auto expr = testutil::LogicalMinExpr( - {testutil::LogicalMinExpr( +TEST_F(MinimumFunctionTest, StringType) { + auto expr = testutil::MinimumExpr( + {testutil::MinimumExpr( {SharedConstant(Value("a")), SharedConstant(Value("b"))}), SharedConstant(Value("c"))}); EXPECT_THAT(EvaluateExpr(*expr), Returns(Value("a"))); // Min(Min("a", "b"), "c") -> "a" } -TEST_F(LogicalMinimumFunctionTest, MixedType) { +TEST_F(MinimumFunctionTest, MixedType) { // Type order: Null < Bool < Number < Timestamp < String < Blob < Ref < // GeoPoint < Array < Map - auto expr = testutil::LogicalMinExpr( + auto expr = testutil::MinimumExpr( {SharedConstant(Value(1LL)), - testutil::LogicalMinExpr( + testutil::MinimumExpr( {SharedConstant(Value("1")), SharedConstant(Value(0LL))})}); EXPECT_THAT( EvaluateExpr(*expr), Returns(Value(0LL))); // Min(1, Min("1", 0)) -> 0 (Number < String) } -TEST_F(LogicalMinimumFunctionTest, OnlyNullAndErrorReturnsNull) { - auto expr = testutil::LogicalMinExpr({NullExpr, ErrorExpr()}); +TEST_F(MinimumFunctionTest, OnlyNullAndErrorReturnsNull) { + auto expr = testutil::MinimumExpr({NullExpr, ErrorExpr()}); EXPECT_THAT(EvaluateExpr(*expr, error_doc_), ReturnsNull()); } -TEST_F(LogicalMinimumFunctionTest, NanAndNumbers) { +TEST_F(MinimumFunctionTest, NanAndNumbers) { // NaN is handled specially; it's considered the minimum unless skipped. - auto expr = testutil::LogicalMinExpr({NanExpr, SharedConstant(Value(0LL))}); + auto expr = testutil::MinimumExpr({NanExpr, SharedConstant(Value(0LL))}); EXPECT_THAT(EvaluateExpr(*expr), Returns(Value(NAN))); // Min(NaN, 0) -> NaN - auto expr2 = testutil::LogicalMinExpr({SharedConstant(Value(0LL)), NanExpr}); + auto expr2 = testutil::MinimumExpr({SharedConstant(Value(0LL)), NanExpr}); EXPECT_THAT(EvaluateExpr(*expr2), Returns(Value(NAN))); // Min(0, NaN) -> NaN - auto expr3 = testutil::LogicalMinExpr({NanExpr, NullExpr, ErrorExpr()}); + auto expr3 = testutil::MinimumExpr({NanExpr, NullExpr, ErrorExpr()}); EXPECT_THAT(EvaluateExpr(*expr3, error_doc_), Returns(Value(NAN))); // Min(NaN, Null, Error) -> NaN - auto expr4 = testutil::LogicalMinExpr({NanExpr, ErrorExpr()}); + auto expr4 = testutil::MinimumExpr({NanExpr, ErrorExpr()}); EXPECT_THAT(EvaluateExpr(*expr4, error_doc_), Returns(Value(NAN))); // Min(NaN, Error) -> NaN } -TEST_F(LogicalMinimumFunctionTest, ErrorInputSkip) { - auto expr = - testutil::LogicalMinExpr({ErrorExpr(), SharedConstant(Value(1LL))}); +TEST_F(MinimumFunctionTest, ErrorInputSkip) { + auto expr = testutil::MinimumExpr({ErrorExpr(), SharedConstant(Value(1LL))}); EXPECT_THAT(EvaluateExpr(*expr, error_doc_), Returns(Value(1LL))); } -TEST_F(LogicalMinimumFunctionTest, NullInputSkip) { - auto expr = testutil::LogicalMinExpr({NullExpr, SharedConstant(Value(1LL))}); +TEST_F(MinimumFunctionTest, NullInputSkip) { + auto expr = testutil::MinimumExpr({NullExpr, SharedConstant(Value(1LL))}); EXPECT_THAT(EvaluateExpr(*expr), Returns(Value(1LL))); } -TEST_F(LogicalMinimumFunctionTest, EquivalentNumerics) { - auto expr = testutil::LogicalMinExpr( +TEST_F(MinimumFunctionTest, EquivalentNumerics) { + auto expr = testutil::MinimumExpr( {SharedConstant(Value(1LL)), SharedConstant(Value(1.0))}); // Min(1, 1.0) -> 1 (or 1.0, they are equivalent) EXPECT_THAT(EvaluateExpr(*expr), Returns(Value(1LL))); @@ -653,16 +651,16 @@ TEST_F(LogicalMinimumFunctionTest, EquivalentNumerics) { class NotFunctionTest : public LogicalExpressionsTest {}; TEST_F(NotFunctionTest, TrueToFalse) { - // Using EqExpr from comparison_test helpers for simplicity - auto true_cond = testutil::EqExpr( + // Using EqualExpr from comparison_test helpers for simplicity + auto true_cond = testutil::EqualExpr( {SharedConstant(Value(1LL)), SharedConstant(Value(1LL))}); EXPECT_THAT(EvaluateExpr(*testutil::NotExpr(true_cond)), Returns(Value(false))); } TEST_F(NotFunctionTest, FalseToTrue) { - // Using NeqExpr from comparison_test helpers for simplicity - auto false_cond = testutil::NeqExpr( + // Using NotEqualExpr from comparison_test helpers for simplicity + auto false_cond = testutil::NotEqualExpr( {SharedConstant(Value(1LL)), SharedConstant(Value(1LL))}); EXPECT_THAT(EvaluateExpr(*testutil::NotExpr(false_cond)), Returns(Value(true))); diff --git a/Firestore/core/test/unit/core/expressions/mirroring_semantics_test.cc b/Firestore/core/test/unit/core/expressions/mirroring_semantics_test.cc index e84c450a512..3a46b01514a 100644 --- a/Firestore/core/test/unit/core/expressions/mirroring_semantics_test.cc +++ b/Firestore/core/test/unit/core/expressions/mirroring_semantics_test.cc @@ -49,29 +49,29 @@ using testutil::CharLengthExpr; using testutil::DivideExpr; using testutil::EndsWithExpr; using testutil::EqAnyExpr; -using testutil::EqExpr; +using testutil::EqualExpr; using testutil::EvaluateExpr; -using testutil::GteExpr; -using testutil::GtExpr; +using testutil::GreaterThanExpr; +using testutil::GreaterThanOrEqualExpr; using testutil::IsNanExpr; using testutil::IsNotNanExpr; +using testutil::LessThanExpr; +using testutil::LessThanOrEqualExpr; using testutil::LikeExpr; -using testutil::LteExpr; -using testutil::LtExpr; using testutil::ModExpr; using testutil::MultiplyExpr; -using testutil::NeqExpr; using testutil::NotEqAnyExpr; +using testutil::NotEqualExpr; using testutil::RegexContainsExpr; using testutil::RegexMatchExpr; using testutil::Returns; using testutil::ReturnsError; using testutil::ReturnsNull; -using testutil::ReverseExpr; using testutil::SharedConstant; using testutil::StartsWithExpr; -using testutil::StrConcatExpr; -using testutil::StrContainsExpr; +using testutil::StringConcatExpr; +using testutil::StringContainsExpr; +using testutil::StringReverseExpr; using testutil::SubtractExpr; using testutil::TimestampToUnixMicrosExpr; using testutil::TimestampToUnixMillisExpr; @@ -112,7 +112,7 @@ TEST_F(MirroringSemanticsTest, UnaryFunctionInputMirroring) { [](auto v) { return IsNanExpr(v); }, [](auto v) { return IsNotNanExpr(v); }, [](auto v) { return ArrayLengthExpr(v); }, - [](auto v) { return ReverseExpr(v); }, + [](auto v) { return StringReverseExpr(v); }, [](auto v) { return CharLengthExpr(v); }, [](auto v) { return ByteLengthExpr(v); }, [](auto v) { return ToLowerExpr(v); }, @@ -162,7 +162,7 @@ TEST_F(MirroringSemanticsTest, BinaryFunctionInputMirroring) { using BinaryBuilder = std::function( std::shared_ptr, std::shared_ptr)>; - // Note: Variadic functions like add, multiply, str_concat are tested + // Note: Variadic functions like add, multiply, string_concat are tested // with their base binary case here. const std::vector binary_function_builders = { // Arithmetic (Variadic, base is binary) @@ -172,12 +172,12 @@ TEST_F(MirroringSemanticsTest, BinaryFunctionInputMirroring) { [](auto v1, auto v2) { return DivideExpr({v1, v2}); }, [](auto v1, auto v2) { return ModExpr({v1, v2}); }, // Comparison - [](auto v1, auto v2) { return EqExpr({v1, v2}); }, - [](auto v1, auto v2) { return NeqExpr({v1, v2}); }, - [](auto v1, auto v2) { return LtExpr({v1, v2}); }, - [](auto v1, auto v2) { return LteExpr({v1, v2}); }, - [](auto v1, auto v2) { return GtExpr({v1, v2}); }, - [](auto v1, auto v2) { return GteExpr({v1, v2}); }, + [](auto v1, auto v2) { return EqualExpr({v1, v2}); }, + [](auto v1, auto v2) { return NotEqualExpr({v1, v2}); }, + [](auto v1, auto v2) { return LessThanExpr({v1, v2}); }, + [](auto v1, auto v2) { return LessThanOrEqualExpr({v1, v2}); }, + [](auto v1, auto v2) { return GreaterThanExpr({v1, v2}); }, + [](auto v1, auto v2) { return GreaterThanOrEqualExpr({v1, v2}); }, // Array [](auto v1, auto v2) { return ArrayContainsExpr({v1, v2}); }, [](auto v1, auto v2) { return ArrayContainsAllExpr({v1, v2}); }, @@ -188,10 +188,10 @@ TEST_F(MirroringSemanticsTest, BinaryFunctionInputMirroring) { [](auto v1, auto v2) { return LikeExpr(v1, v2); }, [](auto v1, auto v2) { return RegexContainsExpr(v1, v2); }, [](auto v1, auto v2) { return RegexMatchExpr(v1, v2); }, - [](auto v1, auto v2) { return StrContainsExpr(v1, v2); }, + [](auto v1, auto v2) { return StringContainsExpr(v1, v2); }, [](auto v1, auto v2) { return StartsWithExpr(v1, v2); }, [](auto v1, auto v2) { return EndsWithExpr(v1, v2); }, - [](auto v1, auto v2) { return StrConcatExpr({v1, v2}); } + [](auto v1, auto v2) { return StringConcatExpr({v1, v2}); } // TODO(b/351084804): mapGet is not implemented yet }; diff --git a/Firestore/core/test/unit/core/expressions/string_test.cc b/Firestore/core/test/unit/core/expressions/string_test.cc index 404f9f1eb0a..dba96829ec1 100644 --- a/Firestore/core/test/unit/core/expressions/string_test.cc +++ b/Firestore/core/test/unit/core/expressions/string_test.cc @@ -46,11 +46,11 @@ using testutil::RegexMatchExpr; using testutil::Returns; using testutil::ReturnsError; using testutil::ReturnsNull; // If needed for string functions -using testutil::ReverseExpr; using testutil::SharedConstant; using testutil::StartsWithExpr; -using testutil::StrConcatExpr; -using testutil::StrContainsExpr; +using testutil::StringConcatExpr; +using testutil::StringContainsExpr; +using testutil::StringReverseExpr; using testutil::ToLowerExpr; using testutil::ToUpperExpr; using testutil::TrimExpr; @@ -69,7 +69,7 @@ class StrContainsTest : public ::testing::Test {}; class ToLowerTest : public ::testing::Test {}; class ToUpperTest : public ::testing::Test {}; class TrimTest : public ::testing::Test {}; -class ReverseTest : public ::testing::Test {}; +class StringReverseTest : public ::testing::Test {}; // --- ByteLength Tests --- TEST_F(ByteLengthTest, EmptyString) { @@ -346,21 +346,21 @@ TEST_F(CharLengthTest, LargeString) { // --- StrConcat Tests --- TEST_F(StrConcatTest, MultipleStringChildrenReturnsCombination) { EXPECT_THAT( - EvaluateExpr(*StrConcatExpr( + EvaluateExpr(*StringConcatExpr( {SharedConstant("foo"), SharedConstant(" "), SharedConstant("bar")})), Returns(Value("foo bar"))); } TEST_F(StrConcatTest, MultipleNonStringChildrenReturnsError) { EXPECT_THAT( - EvaluateExpr(*StrConcatExpr({SharedConstant("foo"), - SharedConstant(static_cast(42LL)), - SharedConstant("bar")})), + EvaluateExpr(*StringConcatExpr( + {SharedConstant("foo"), SharedConstant(static_cast(42LL)), + SharedConstant("bar")})), ReturnsError()); } TEST_F(StrConcatTest, MultipleCalls) { - auto func = StrConcatExpr( + auto func = StringConcatExpr( {SharedConstant("foo"), SharedConstant(" "), SharedConstant("bar")}); EXPECT_THAT(EvaluateExpr(*func), Returns(Value("foo bar"))); EXPECT_THAT(EvaluateExpr(*func), @@ -377,7 +377,7 @@ TEST_F(StrConcatTest, LargeNumberOfInputs) { expected_result += "a"; } // Need to construct FunctionExpr with vector directly - auto func = StrConcatExpr(std::move(args)); + auto func = StringConcatExpr(std::move(args)); EXPECT_THAT(EvaluateExpr(*func), Returns(Value(expected_result))); } @@ -386,9 +386,9 @@ TEST_F(StrConcatTest, LargeStrings) { std::string b500(500, 'b'); std::string c500(500, 'c'); // Use .c_str() for std::string variables - auto func = - StrConcatExpr({SharedConstant(a500.c_str()), SharedConstant(b500.c_str()), - SharedConstant(c500.c_str())}); + auto func = StringConcatExpr({SharedConstant(a500.c_str()), + SharedConstant(b500.c_str()), + SharedConstant(c500.c_str())}); EXPECT_THAT(EvaluateExpr(*func), Returns(Value(a500 + b500 + c500))); } @@ -678,51 +678,51 @@ TEST_F(StartsWithTest, GetLargePrefixReturnsFalse) { // --- StrContains Tests --- TEST_F(StrContainsTest, ValueNonStringIsError) { EXPECT_THAT( - EvaluateExpr(*StrContainsExpr(SharedConstant(static_cast(42LL)), - SharedConstant("value"))), + EvaluateExpr(*StringContainsExpr( + SharedConstant(static_cast(42LL)), SharedConstant("value"))), ReturnsError()); } TEST_F(StrContainsTest, SubStringNonStringIsError) { - EXPECT_THAT(EvaluateExpr( - *StrContainsExpr(SharedConstant("search space"), - SharedConstant(static_cast(42LL)))), + EXPECT_THAT(EvaluateExpr(*StringContainsExpr( + SharedConstant("search space"), + SharedConstant(static_cast(42LL)))), ReturnsError()); } TEST_F(StrContainsTest, ExecuteTrue) { - EXPECT_THAT(EvaluateExpr( - *StrContainsExpr(SharedConstant("abc"), SharedConstant("c"))), + EXPECT_THAT(EvaluateExpr(*StringContainsExpr(SharedConstant("abc"), + SharedConstant("c"))), Returns(Value(true))); - EXPECT_THAT(EvaluateExpr(*StrContainsExpr(SharedConstant("abc"), - SharedConstant("bc"))), + EXPECT_THAT(EvaluateExpr(*StringContainsExpr(SharedConstant("abc"), + SharedConstant("bc"))), Returns(Value(true))); - EXPECT_THAT(EvaluateExpr(*StrContainsExpr(SharedConstant("abc"), - SharedConstant("abc"))), + EXPECT_THAT(EvaluateExpr(*StringContainsExpr(SharedConstant("abc"), + SharedConstant("abc"))), + Returns(Value(true))); + EXPECT_THAT(EvaluateExpr(*StringContainsExpr(SharedConstant("abc"), + SharedConstant(""))), Returns(Value(true))); EXPECT_THAT( - EvaluateExpr(*StrContainsExpr(SharedConstant("abc"), SharedConstant(""))), - Returns(Value(true))); - EXPECT_THAT( - EvaluateExpr(*StrContainsExpr(SharedConstant(""), SharedConstant(""))), + EvaluateExpr(*StringContainsExpr(SharedConstant(""), SharedConstant(""))), Returns(Value(true))); - EXPECT_THAT(EvaluateExpr( - *StrContainsExpr(SharedConstant("☃☃☃"), SharedConstant("☃"))), + EXPECT_THAT(EvaluateExpr(*StringContainsExpr(SharedConstant("☃☃☃"), + SharedConstant("☃"))), Returns(Value(true))); } TEST_F(StrContainsTest, ExecuteFalse) { - EXPECT_THAT(EvaluateExpr(*StrContainsExpr(SharedConstant("abc"), - SharedConstant("abcd"))), + EXPECT_THAT(EvaluateExpr(*StringContainsExpr(SharedConstant("abc"), + SharedConstant("abcd"))), + Returns(Value(false))); + EXPECT_THAT(EvaluateExpr(*StringContainsExpr(SharedConstant("abc"), + SharedConstant("d"))), Returns(Value(false))); EXPECT_THAT(EvaluateExpr( - *StrContainsExpr(SharedConstant("abc"), SharedConstant("d"))), + *StringContainsExpr(SharedConstant(""), SharedConstant("a"))), Returns(Value(false))); - EXPECT_THAT( - EvaluateExpr(*StrContainsExpr(SharedConstant(""), SharedConstant("a"))), - Returns(Value(false))); - EXPECT_THAT(EvaluateExpr(*StrContainsExpr(SharedConstant(""), - SharedConstant("abcde"))), + EXPECT_THAT(EvaluateExpr(*StringContainsExpr(SharedConstant(""), + SharedConstant("abcde"))), Returns(Value(false))); } @@ -800,30 +800,30 @@ TEST_F(TrimTest, Null) { EXPECT_THAT(EvaluateExpr(*TrimExpr(SharedConstant(nullptr))), ReturnsNull()); } -// --- Reverse Tests --- -TEST_F(ReverseTest, Basic) { - EXPECT_THAT(EvaluateExpr(*ReverseExpr(SharedConstant("abc"))), +// --- StringReverse Tests --- +TEST_F(StringReverseTest, Basic) { + EXPECT_THAT(EvaluateExpr(*StringReverseExpr(SharedConstant("abc"))), Returns(Value("cba"))); } -TEST_F(ReverseTest, Empty) { - EXPECT_THAT(EvaluateExpr(*ReverseExpr(SharedConstant(""))), +TEST_F(StringReverseTest, Empty) { + EXPECT_THAT(EvaluateExpr(*StringReverseExpr(SharedConstant(""))), Returns(Value(""))); } -TEST_F(ReverseTest, Unicode) { - EXPECT_THAT(EvaluateExpr(*ReverseExpr(SharedConstant("aé好🂡"))), +TEST_F(StringReverseTest, Unicode) { + EXPECT_THAT(EvaluateExpr(*StringReverseExpr(SharedConstant("aé好🂡"))), Returns(Value("🂡好éa"))); } -TEST_F(ReverseTest, NonString) { - EXPECT_THAT( - EvaluateExpr(*ReverseExpr(SharedConstant(static_cast(123LL)))), - ReturnsError()); +TEST_F(StringReverseTest, NonString) { + EXPECT_THAT(EvaluateExpr(*StringReverseExpr( + SharedConstant(static_cast(123LL)))), + ReturnsError()); } -TEST_F(ReverseTest, Null) { - EXPECT_THAT(EvaluateExpr(*ReverseExpr(SharedConstant(nullptr))), +TEST_F(StringReverseTest, Null) { + EXPECT_THAT(EvaluateExpr(*StringReverseExpr(SharedConstant(nullptr))), ReturnsNull()); } diff --git a/Firestore/core/test/unit/core/pipeline/canonify_eq_test.cc b/Firestore/core/test/unit/core/pipeline/canonify_eq_test.cc index 7a8f4caab57..14ff272dc02 100644 --- a/Firestore/core/test/unit/core/pipeline/canonify_eq_test.cc +++ b/Firestore/core/test/unit/core/pipeline/canonify_eq_test.cc @@ -71,7 +71,7 @@ using testutil::SharedConstant; using testutil::Value; // Expression helpers using testutil::EqAnyExpr; -using testutil::EqExpr; +using testutil::EqualExpr; // Helper to get canonical ID directly for RealtimePipeline std::string GetPipelineCanonicalId(const RealtimePipeline& pipeline) { @@ -119,25 +119,27 @@ class CanonifyEqPipelineTest : public ::testing::Test { TEST_F(CanonifyEqPipelineTest, CanonifySimpleWhere) { RealtimePipeline p = StartPipeline("test"); - p = p.AddingStage(std::make_shared(EqExpr( + p = p.AddingStage(std::make_shared(EqualExpr( {std::make_shared("foo"), SharedConstant(Value(42LL))}))); - EXPECT_EQ(GetPipelineCanonicalId(p), - "collection(test)|where(fn(eq[fld(foo),cst(42)]))|sort(fld(__name__" - ")asc)"); + EXPECT_EQ( + GetPipelineCanonicalId(p), + "collection(test)|where(fn(equal[fld(foo),cst(42)]))|sort(fld(__name__" + ")asc)"); } TEST_F(CanonifyEqPipelineTest, CanonifyMultipleStages) { RealtimePipeline p = StartPipeline("test"); - p = p.AddingStage(std::make_shared(EqExpr( + p = p.AddingStage(std::make_shared(EqualExpr( {std::make_shared("foo"), SharedConstant(Value(42LL))}))); p = p.AddingStage(std::make_shared(10)); p = p.AddingStage(std::make_shared( std::vector{Ordering(std::make_shared("bar"), api::Ordering::Direction::DESCENDING)})); - EXPECT_EQ(GetPipelineCanonicalId(p), - "collection(test)|where(fn(eq[fld(foo),cst(42)]))|sort(fld(__name__" - ")asc)|limit(10)|sort(fld(bar)desc,fld(__name__)asc)"); + EXPECT_EQ( + GetPipelineCanonicalId(p), + "collection(test)|where(fn(equal[fld(foo),cst(42)]))|sort(fld(__name__" + ")asc)|limit(10)|sort(fld(bar)desc,fld(__name__)asc)"); } // TEST_F(CanonifyEqPipelineTest, CanonifyAddFields) { @@ -228,7 +230,7 @@ TEST_F(CanonifyEqPipelineTest, CanonifyCollectionGroupSource) { // Value("b")))))); // // EXPECT_EQ(GetPipelineCanonicalId(p), -// "collection(/foo)|where(fn(eq_any,[fld(bar),list([cst(\"a\"),cst(\"b\")])]))|sort(fld(__name__)asc)"); +// collection(/foo)|where(fn(equal_any,[fld(bar),list([cst("a"),cst("b")])]))|sort(fld(__name__)asc)); // } // =================================================================== @@ -239,11 +241,11 @@ TEST_F(CanonifyEqPipelineTest, CanonifyCollectionGroupSource) { TEST_F(CanonifyEqPipelineTest, EqReturnsTrueForIdenticalPipelines) { RealtimePipeline p1 = StartPipeline("test"); - p1 = p1.AddingStage(std::make_shared(EqExpr( + p1 = p1.AddingStage(std::make_shared(EqualExpr( {std::make_shared("foo"), SharedConstant(Value(42LL))}))); RealtimePipeline p2 = StartPipeline("test"); - p2 = p2.AddingStage(std::make_shared(EqExpr( + p2 = p2.AddingStage(std::make_shared(EqualExpr( {std::make_shared("foo"), SharedConstant(Value(42LL))}))); QueryOrPipeline v1 = QueryOrPipeline(p1); @@ -253,7 +255,7 @@ TEST_F(CanonifyEqPipelineTest, EqReturnsTrueForIdenticalPipelines) { TEST_F(CanonifyEqPipelineTest, EqReturnsFalseForDifferentStages) { RealtimePipeline p1 = StartPipeline("test"); - p1 = p1.AddingStage(std::make_shared(EqExpr( + p1 = p1.AddingStage(std::make_shared(EqualExpr( {std::make_shared("foo"), SharedConstant(Value(42LL))}))); RealtimePipeline p2 = StartPipeline("test"); @@ -266,13 +268,13 @@ TEST_F(CanonifyEqPipelineTest, EqReturnsFalseForDifferentStages) { TEST_F(CanonifyEqPipelineTest, EqReturnsFalseForDifferentParamsInStage) { RealtimePipeline p1 = StartPipeline("test"); - p1 = p1.AddingStage(std::make_shared(EqExpr( + p1 = p1.AddingStage(std::make_shared(EqualExpr( {std::make_shared("foo"), SharedConstant(Value(42LL))}))); RealtimePipeline p2 = StartPipeline("test"); p2 = p2.AddingStage(std::make_shared( - EqExpr({std::make_shared("bar"), - SharedConstant(Value(42LL))}))); // Different field + EqualExpr({std::make_shared("bar"), + SharedConstant(Value(42LL))}))); // Different field QueryOrPipeline v1 = QueryOrPipeline(p1); QueryOrPipeline v2 = QueryOrPipeline(p2); @@ -281,13 +283,13 @@ TEST_F(CanonifyEqPipelineTest, EqReturnsFalseForDifferentParamsInStage) { TEST_F(CanonifyEqPipelineTest, EqReturnsFalseForDifferentStageOrder) { RealtimePipeline p1 = StartPipeline("test"); - p1 = p1.AddingStage(std::make_shared(EqExpr( + p1 = p1.AddingStage(std::make_shared(EqualExpr( {std::make_shared("foo"), SharedConstant(Value(42LL))}))); p1 = p1.AddingStage(std::make_shared(10)); RealtimePipeline p2 = StartPipeline("test"); p2 = p2.AddingStage(std::make_shared(10)); - p2 = p2.AddingStage(std::make_shared(EqExpr( + p2 = p2.AddingStage(std::make_shared(EqualExpr( {std::make_shared("foo"), SharedConstant(Value(42LL))}))); QueryOrPipeline v1 = QueryOrPipeline(p1); diff --git a/Firestore/core/test/unit/core/pipeline/collection_group_test.cc b/Firestore/core/test/unit/core/pipeline/collection_group_test.cc index 4f12261a038..b350caba5ed 100644 --- a/Firestore/core/test/unit/core/pipeline/collection_group_test.cc +++ b/Firestore/core/test/unit/core/pipeline/collection_group_test.cc @@ -55,9 +55,9 @@ using testutil::Array; using testutil::ArrayContainsExpr; using testutil::Doc; using testutil::EqAnyExpr; -using testutil::GtExpr; +using testutil::GreaterThanExpr; using testutil::Map; -using testutil::NeqExpr; +using testutil::NotEqualExpr; using testutil::SharedConstant; using testutil::Value; @@ -229,8 +229,9 @@ TEST_F(CollectionGroupTest, WhereOnValues) { TEST_F(CollectionGroupTest, WhereInequalityOnValues) { RealtimePipeline pipeline = StartPipeline("users"); - auto where_expr = GtExpr({std::make_shared("score"), - SharedConstant(static_cast(80LL))}); + auto where_expr = + GreaterThanExpr({std::make_shared("score"), + SharedConstant(static_cast(80LL))}); pipeline = pipeline.AddingStage(std::make_shared(where_expr)); auto doc1 = Doc("users/bob", 1000, Map("score", 90LL)); @@ -249,8 +250,8 @@ TEST_F(CollectionGroupTest, WhereInequalityOnValues) { TEST_F(CollectionGroupTest, WhereNotEqualOnValues) { RealtimePipeline pipeline = StartPipeline("users"); - auto where_expr = NeqExpr({std::make_shared("score"), - SharedConstant(static_cast(50LL))}); + auto where_expr = NotEqualExpr({std::make_shared("score"), + SharedConstant(static_cast(50LL))}); pipeline = pipeline.AddingStage(std::make_shared(where_expr)); auto doc1 = Doc("users/bob", 1000, Map("score", 90LL)); diff --git a/Firestore/core/test/unit/core/pipeline/collection_test.cc b/Firestore/core/test/unit/core/pipeline/collection_test.cc index b5962732de1..8c70855cf91 100644 --- a/Firestore/core/test/unit/core/pipeline/collection_test.cc +++ b/Firestore/core/test/unit/core/pipeline/collection_test.cc @@ -54,9 +54,9 @@ using testutil::Array; using testutil::ArrayContainsExpr; using testutil::Doc; using testutil::EqAnyExpr; -using testutil::GtExpr; +using testutil::GreaterThanExpr; using testutil::Map; -using testutil::NeqExpr; +using testutil::NotEqualExpr; using testutil::SharedConstant; using testutil::Value; @@ -223,8 +223,9 @@ TEST_F(CollectionTest, WhereOnValues) { TEST_F(CollectionTest, WhereInequalityOnValues) { RealtimePipeline pipeline = StartPipeline("/users"); // Use RealtimePipeline - auto where_expr = GtExpr({std::make_shared("score"), - SharedConstant(static_cast(80LL))}); + auto where_expr = + GreaterThanExpr({std::make_shared("score"), + SharedConstant(static_cast(80LL))}); pipeline = pipeline.AddingStage(std::make_shared(where_expr)); auto doc1 = Doc("users/bob", 1000, Map("score", 90LL)); @@ -238,8 +239,8 @@ TEST_F(CollectionTest, WhereInequalityOnValues) { TEST_F(CollectionTest, WhereNotEqualOnValues) { RealtimePipeline pipeline = StartPipeline("/users"); // Use RealtimePipeline - auto where_expr = NeqExpr({std::make_shared("score"), - SharedConstant(static_cast(50LL))}); + auto where_expr = NotEqualExpr({std::make_shared("score"), + SharedConstant(static_cast(50LL))}); pipeline = pipeline.AddingStage(std::make_shared(where_expr)); auto doc1 = Doc("users/bob", 1000, Map("score", 90LL)); diff --git a/Firestore/core/test/unit/core/pipeline/complex_test.cc b/Firestore/core/test/unit/core/pipeline/complex_test.cc index abfe8b23d51..0c7b365e54f 100644 --- a/Firestore/core/test/unit/core/pipeline/complex_test.cc +++ b/Firestore/core/test/unit/core/pipeline/complex_test.cc @@ -64,12 +64,12 @@ using testutil::AddExpr; using testutil::AndExpr; using testutil::ArrayContainsAnyExpr; using testutil::EqAnyExpr; -using testutil::EqExpr; -using testutil::GtExpr; -using testutil::LteExpr; -using testutil::LtExpr; -using testutil::NeqExpr; +using testutil::EqualExpr; +using testutil::GreaterThanExpr; +using testutil::LessThanExpr; +using testutil::LessThanOrEqualExpr; using testutil::NotEqAnyExpr; +using testutil::NotEqualExpr; using testutil::OrExpr; using testutil::Value; @@ -129,8 +129,8 @@ TEST_F(ComplexPipelineTest, WhereWithMaxNumberOfStages) { for (int i = 1; i <= num_of_fields; ++i) { std::string field_name = "field_" + std::to_string(i); pipeline = pipeline.AddingStage(std::make_shared( - GtExpr({std::make_shared(field_name), - SharedConstant(static_cast(0LL))}))); + GreaterThanExpr({std::make_shared(field_name), + SharedConstant(static_cast(0LL))}))); } EXPECT_THAT(RunPipeline(pipeline, documents), @@ -391,7 +391,7 @@ TEST_F(ComplexPipelineTest, WhereWithNestedAddFunctionMaxDepth) { RealtimePipeline pipeline = StartPipeline("/" + COLLECTION_ID); pipeline = pipeline.AddingStage(std::make_shared( - GtExpr({add_func, SharedConstant(static_cast(0LL))}))); + GreaterThanExpr({add_func, SharedConstant(static_cast(0LL))}))); // Since field_1 starts at 0, adding 1 repeatedly will always result in > 0 EXPECT_THAT(RunPipeline(pipeline, documents), @@ -410,8 +410,8 @@ TEST_F(ComplexPipelineTest, WhereWithLargeNumberOrs) { or_conditions.reserve(num_of_fields); for (int i = 1; i <= num_of_fields; ++i) { std::string field_name = "field_" + std::to_string(i); - // Use LteExpr to match the TS test logic - or_conditions.push_back(LteExpr( + // Use LessThanOrEqualExpr to match the TS test logic + or_conditions.push_back(LessThanOrEqualExpr( {std::make_shared(field_name), SharedConstant(max_value)})); } @@ -439,12 +439,12 @@ TEST_F(ComplexPipelineTest, WhereWithLargeNumberOfConjunctions) { for (int i = 1; i <= num_of_fields; ++i) { std::string field_name = "field_" + std::to_string(i); and_conditions1.push_back( - GtExpr({std::make_shared(field_name), - SharedConstant(static_cast(0LL))})); - // Use LtExpr and a large number for the second condition + GreaterThanExpr({std::make_shared(field_name), + SharedConstant(static_cast(0LL))})); + // Use LessThanExpr and a large number for the second condition and_conditions2.push_back( - LtExpr({std::make_shared(field_name), - SharedConstant(std::numeric_limits::max())})); + LessThanExpr({std::make_shared(field_name), + SharedConstant(std::numeric_limits::max())})); } RealtimePipeline pipeline = StartPipeline("/" + COLLECTION_ID); diff --git a/Firestore/core/test/unit/core/pipeline/disjunctive_test.cc b/Firestore/core/test/unit/core/pipeline/disjunctive_test.cc index f9c89873c24..497554d7bff 100644 --- a/Firestore/core/test/unit/core/pipeline/disjunctive_test.cc +++ b/Firestore/core/test/unit/core/pipeline/disjunctive_test.cc @@ -65,16 +65,16 @@ using testutil::ArrayContainsAllExpr; using testutil::ArrayContainsAnyExpr; using testutil::ArrayContainsExpr; using testutil::EqAnyExpr; -using testutil::EqExpr; -using testutil::GteExpr; -using testutil::GtExpr; +using testutil::EqualExpr; +using testutil::GreaterThanExpr; +using testutil::GreaterThanOrEqualExpr; using testutil::IsNanExpr; using testutil::IsNullExpr; +using testutil::LessThanExpr; +using testutil::LessThanOrEqualExpr; using testutil::LikeExpr; -using testutil::LteExpr; -using testutil::LtExpr; -using testutil::NeqExpr; using testutil::NotEqAnyExpr; +using testutil::NotEqualExpr; using testutil::NotExpr; using testutil::OrExpr; using testutil::XorExpr; @@ -261,7 +261,7 @@ TEST_F(DisjunctivePipelineTest, EqAnyWithAdditionalEqualityDifferentFields) { std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob"), Value("charlie"), Value("diane"), Value("eric")))), - EqExpr( + EqualExpr( {std::make_shared("age"), SharedConstant(Value(10.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( @@ -283,8 +283,8 @@ TEST_F(DisjunctivePipelineTest, EqAnyWithAdditionalEqualitySameField) { AndExpr({EqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("diane"), Value("eric")))), - EqExpr({std::make_shared("name"), - SharedConstant(Value("eric"))})}))); + EqualExpr({std::make_shared("name"), + SharedConstant(Value("eric"))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc5)); } @@ -300,8 +300,8 @@ TEST_F(DisjunctivePipelineTest, pipeline = pipeline.AddingStage(std::make_shared( AndExpr({EqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob")))), - EqExpr({std::make_shared("name"), - SharedConstant(Value("other"))})}))); + EqualExpr({std::make_shared("name"), + SharedConstant(Value("other"))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); // Expect empty result @@ -321,8 +321,9 @@ TEST_F(DisjunctivePipelineTest, EqAnyWithInequalitiesExclusiveRange) { {EqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob"), Value("charlie"), Value("diane")))), - GtExpr({std::make_shared("age"), SharedConstant(Value(10.0))}), - LtExpr( + GreaterThanExpr( + {std::make_shared("age"), SharedConstant(Value(10.0))}), + LessThanExpr( {std::make_shared("age"), SharedConstant(Value(100.0))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), @@ -343,8 +344,9 @@ TEST_F(DisjunctivePipelineTest, EqAnyWithInequalitiesInclusiveRange) { {EqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob"), Value("charlie"), Value("diane")))), - GteExpr({std::make_shared("age"), SharedConstant(Value(10.0))}), - LteExpr( + GreaterThanOrEqualExpr( + {std::make_shared("age"), SharedConstant(Value(10.0))}), + LessThanOrEqualExpr( {std::make_shared("age"), SharedConstant(Value(100.0))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), @@ -365,8 +367,9 @@ TEST_F(DisjunctivePipelineTest, EqAnyWithInequalitiesAndSort) { {EqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob"), Value("charlie"), Value("diane")))), - GtExpr({std::make_shared("age"), SharedConstant(Value(10.0))}), - LtExpr( + GreaterThanExpr( + {std::make_shared("age"), SharedConstant(Value(10.0))}), + LessThanExpr( {std::make_shared("age"), SharedConstant(Value(100.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( @@ -389,7 +392,7 @@ TEST_F(DisjunctivePipelineTest, EqAnyWithNotEqual) { {EqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob"), Value("charlie"), Value("diane")))), - NeqExpr( + NotEqualExpr( {std::make_shared("age"), SharedConstant(Value(100.0))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), @@ -456,7 +459,7 @@ TEST_F(DisjunctivePipelineTest, EqAnyWithExtraEqualitySortOnEqAnyField) { std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob"), Value("charlie"), Value("diane"), Value("eric")))), - EqExpr( + EqualExpr( {std::make_shared("age"), SharedConstant(Value(10.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( @@ -479,7 +482,7 @@ TEST_F(DisjunctivePipelineTest, EqAnyWithExtraEqualitySortOnEquality) { std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob"), Value("charlie"), Value("diane"), Value("eric")))), - EqExpr( + EqualExpr( {std::make_shared("age"), SharedConstant(Value(10.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( @@ -505,7 +508,7 @@ TEST_F(DisjunctivePipelineTest, EqAnyWithInequalityOnSameField) { pipeline = pipeline.AddingStage(std::make_shared(AndExpr( {EqAnyExpr(std::make_shared("age"), SharedConstant(Array(Value(10.0), Value(25.0), Value(100.0)))), - GtExpr( + GreaterThanExpr( {std::make_shared("age"), SharedConstant(Value(20.0))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), @@ -531,7 +534,7 @@ TEST_F( {EqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob"), Value("charlie"), Value("diane")))), - GtExpr( + GreaterThanExpr( {std::make_shared("age"), SharedConstant(Value(20.0))})}))); // Sort field is 'age', which is the inequality field, not the EqAny field // 'name'. The TS test name seems misleading based on the sort field used. @@ -700,8 +703,9 @@ TEST_F(DisjunctivePipelineTest, ArrayContainsAnyWithInequality) { // Note: Comparing an array field with an array constant using LT might // not behave as expected in Firestore backend queries. This test // replicates the TS behavior for pipeline evaluation. - LtExpr({std::make_shared("groups"), - SharedConstant(Array(Value(3LL), Value(4LL), Value(5LL)))})}))); + LessThanExpr( + {std::make_shared("groups"), + SharedConstant(Array(Value(3LL), Value(4LL), Value(5LL)))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc1, doc2, doc4)); @@ -745,10 +749,11 @@ TEST_F(DisjunctivePipelineTest, BasicOr) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {EqExpr({std::make_shared("name"), SharedConstant(Value("bob"))}), - EqExpr( - {std::make_shared("age"), SharedConstant(Value(10.0))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + OrExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("bob"))}), + EqualExpr({std::make_shared("age"), + SharedConstant(Value(10.0))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc2, doc4)); @@ -763,11 +768,12 @@ TEST_F(DisjunctivePipelineTest, MultipleOr) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {EqExpr({std::make_shared("name"), SharedConstant(Value("bob"))}), - EqExpr( + {EqualExpr( + {std::make_shared("name"), SharedConstant(Value("bob"))}), + EqualExpr( {std::make_shared("name"), SharedConstant(Value("diane"))}), - EqExpr({std::make_shared("age"), SharedConstant(Value(25.0))}), - EqExpr( + EqualExpr({std::make_shared("age"), SharedConstant(Value(25.0))}), + EqualExpr( {std::make_shared("age"), SharedConstant(Value(100.0))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), @@ -782,15 +788,16 @@ TEST_F(DisjunctivePipelineTest, OrMultipleStages) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {EqExpr({std::make_shared("name"), SharedConstant(Value("bob"))}), - EqExpr( - {std::make_shared("age"), SharedConstant(Value(10.0))})}))); pipeline = pipeline.AddingStage(std::make_shared( - OrExpr({EqExpr({std::make_shared("name"), - SharedConstant(Value("diane"))}), - EqExpr({std::make_shared("age"), - SharedConstant(Value(100.0))})}))); + OrExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("bob"))}), + EqualExpr({std::make_shared("age"), + SharedConstant(Value(10.0))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + OrExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("diane"))}), + EqualExpr({std::make_shared("age"), + SharedConstant(Value(100.0))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc4)); } @@ -804,14 +811,14 @@ TEST_F(DisjunctivePipelineTest, OrTwoConjunctions) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared( - OrExpr({AndExpr({EqExpr({std::make_shared("name"), - SharedConstant(Value("bob"))}), - EqExpr({std::make_shared("age"), - SharedConstant(Value(25.0))})}), - AndExpr({EqExpr({std::make_shared("name"), - SharedConstant(Value("diane"))}), - EqExpr({std::make_shared("age"), - SharedConstant(Value(10.0))})})}))); + OrExpr({AndExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("bob"))}), + EqualExpr({std::make_shared("age"), + SharedConstant(Value(25.0))})}), + AndExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("diane"))}), + EqualExpr({std::make_shared("age"), + SharedConstant(Value(10.0))})})}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc2, doc4)); @@ -826,12 +833,12 @@ TEST_F(DisjunctivePipelineTest, OrWithInAnd) { // Renamed from TS: or_withInAnd RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared( - AndExpr({OrExpr({EqExpr({std::make_shared("name"), - SharedConstant(Value("bob"))}), - EqExpr({std::make_shared("age"), - SharedConstant(Value(10.0))})}), - LtExpr({std::make_shared("age"), - SharedConstant(Value(80.0))})}))); + AndExpr({OrExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("bob"))}), + EqualExpr({std::make_shared("age"), + SharedConstant(Value(10.0))})}), + LessThanExpr({std::make_shared("age"), + SharedConstant(Value(80.0))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc2, doc4)); @@ -846,14 +853,14 @@ TEST_F(DisjunctivePipelineTest, AndOfTwoOrs) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared( - AndExpr({OrExpr({EqExpr({std::make_shared("name"), - SharedConstant(Value("bob"))}), - EqExpr({std::make_shared("age"), - SharedConstant(Value(10.0))})}), - OrExpr({EqExpr({std::make_shared("name"), - SharedConstant(Value("diane"))}), - EqExpr({std::make_shared("age"), - SharedConstant(Value(100.0))})})}))); + AndExpr({OrExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("bob"))}), + EqualExpr({std::make_shared("age"), + SharedConstant(Value(10.0))})}), + OrExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("diane"))}), + EqualExpr({std::make_shared("age"), + SharedConstant(Value(100.0))})})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc4)); } @@ -867,14 +874,14 @@ TEST_F(DisjunctivePipelineTest, OrOfTwoOrs) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared( - OrExpr({OrExpr({EqExpr({std::make_shared("name"), - SharedConstant(Value("bob"))}), - EqExpr({std::make_shared("age"), - SharedConstant(Value(10.0))})}), - OrExpr({EqExpr({std::make_shared("name"), - SharedConstant(Value("diane"))}), - EqExpr({std::make_shared("age"), - SharedConstant(Value(100.0))})})}))); + OrExpr({OrExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("bob"))}), + EqualExpr({std::make_shared("age"), + SharedConstant(Value(10.0))})}), + OrExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("diane"))}), + EqualExpr({std::make_shared("age"), + SharedConstant(Value(100.0))})})}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc2, doc3, doc4)); @@ -888,13 +895,14 @@ TEST_F(DisjunctivePipelineTest, OrWithEmptyRangeInOneDisjunction) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {EqExpr({std::make_shared("name"), SharedConstant(Value("bob"))}), - AndExpr({// This conjunction will always be false - EqExpr({std::make_shared("age"), - SharedConstant(Value(10.0))}), - GtExpr({std::make_shared("age"), - SharedConstant(Value(20.0))})})}))); + pipeline = pipeline.AddingStage(std::make_shared( + OrExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("bob"))}), + AndExpr({// This conjunction will always be false + EqualExpr({std::make_shared("age"), + SharedConstant(Value(10.0))}), + GreaterThanExpr({std::make_shared("age"), + SharedConstant(Value(20.0))})})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc2)); } @@ -907,11 +915,11 @@ TEST_F(DisjunctivePipelineTest, OrWithSort) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage( - std::make_shared(OrExpr({EqExpr({std::make_shared("name"), - SharedConstant(Value("diane"))}), - GtExpr({std::make_shared("age"), - SharedConstant(Value(20.0))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + OrExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("diane"))}), + GreaterThanExpr({std::make_shared("age"), + SharedConstant(Value(20.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("age"), Ordering::Direction::ASCENDING)})); @@ -929,10 +937,11 @@ TEST_F(DisjunctivePipelineTest, OrWithInequalityAndSortSameField) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {LtExpr({std::make_shared("age"), SharedConstant(Value(20.0))}), - GtExpr( - {std::make_shared("age"), SharedConstant(Value(50.0))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + OrExpr({LessThanExpr({std::make_shared("age"), + SharedConstant(Value(20.0))}), + GreaterThanExpr({std::make_shared("age"), + SharedConstant(Value(50.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("age"), Ordering::Direction::ASCENDING)})); @@ -949,10 +958,11 @@ TEST_F(DisjunctivePipelineTest, OrWithInequalityAndSortDifferentFields) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {LtExpr({std::make_shared("age"), SharedConstant(Value(20.0))}), - GtExpr( - {std::make_shared("age"), SharedConstant(Value(50.0))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + OrExpr({LessThanExpr({std::make_shared("age"), + SharedConstant(Value(20.0))}), + GreaterThanExpr({std::make_shared("age"), + SharedConstant(Value(50.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("name"), Ordering::Direction::ASCENDING)})); @@ -975,10 +985,11 @@ TEST_F(DisjunctivePipelineTest, OrWithInequalityAndSortMultipleFields) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4, doc5}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {LtExpr({std::make_shared("age"), SharedConstant(Value(80.0))}), - GtExpr({std::make_shared("height"), - SharedConstant(Value(160.0))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + OrExpr({LessThanExpr({std::make_shared("age"), + SharedConstant(Value(80.0))}), + GreaterThanExpr({std::make_shared("height"), + SharedConstant(Value(160.0))})}))); pipeline = pipeline.AddingStage(std::make_shared(std::vector{ Ordering(std::make_unique("age"), @@ -1004,11 +1015,11 @@ TEST_F(DisjunctivePipelineTest, OrWithSortOnPartialMissingField) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage( - std::make_shared(OrExpr({EqExpr({std::make_shared("name"), - SharedConstant(Value("diane"))}), - GtExpr({std::make_shared("age"), - SharedConstant(Value(20.0))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + OrExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("diane"))}), + GreaterThanExpr({std::make_shared("age"), + SharedConstant(Value(20.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("age"), Ordering::Direction::ASCENDING)})); @@ -1027,11 +1038,11 @@ TEST_F(DisjunctivePipelineTest, OrWithLimit) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage( - std::make_shared(OrExpr({EqExpr({std::make_shared("name"), - SharedConstant(Value("diane"))}), - GtExpr({std::make_shared("age"), - SharedConstant(Value(20.0))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + OrExpr({EqualExpr({std::make_shared("name"), + SharedConstant(Value("diane"))}), + GreaterThanExpr({std::make_shared("age"), + SharedConstant(Value(20.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("age"), Ordering::Direction::ASCENDING)})); @@ -1059,7 +1070,7 @@ TEST_F(DisjunctivePipelineTest, OrIsNullAndEqOnSameField) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {EqExpr({std::make_shared("a"), SharedConstant(Value(1LL))}), + {EqualExpr({std::make_shared("a"), SharedConstant(Value(1LL))}), IsNullExpr(std::make_shared("a"))}))); // Expect docs where a==1 (doc1, doc2, doc3) or a is null (doc4) @@ -1079,7 +1090,7 @@ TEST_F(DisjunctivePipelineTest, OrIsNullAndEqOnDifferentField) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {EqExpr({std::make_shared("b"), SharedConstant(Value(1LL))}), + {EqualExpr({std::make_shared("b"), SharedConstant(Value(1LL))}), IsNullExpr(std::make_shared("a"))}))); // Expect docs where b==1 (doc3) or a is null (doc4) @@ -1100,7 +1111,8 @@ TEST_F(DisjunctivePipelineTest, OrIsNotNullAndEqOnSameField) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(OrExpr({ // Note: TS test uses gt(1), C++ uses gt(1) here too. - GtExpr({std::make_shared("a"), SharedConstant(Value(1LL))}), + GreaterThanExpr( + {std::make_shared("a"), SharedConstant(Value(1LL))}), NotExpr(IsNullExpr(std::make_shared("a"))) // isNotNull }))); @@ -1122,7 +1134,7 @@ TEST_F(DisjunctivePipelineTest, OrIsNotNullAndEqOnDifferentField) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(OrExpr({ - EqExpr({std::make_shared("b"), SharedConstant(Value(1LL))}), + EqualExpr({std::make_shared("b"), SharedConstant(Value(1LL))}), NotExpr(IsNullExpr(std::make_shared("a"))) // isNotNull }))); @@ -1282,7 +1294,7 @@ TEST_F(DisjunctivePipelineTest, NotEqAnyWithAdditionalEqualityDifferentFields) { pipeline = pipeline.AddingStage(std::make_shared(AndExpr( {NotEqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob")))), - EqExpr( + EqualExpr( {std::make_shared("age"), SharedConstant(Value(10.0))})}))); // Expect docs where name is not alice/bob (doc3, doc4, doc5) AND age is 10 @@ -1303,8 +1315,8 @@ TEST_F(DisjunctivePipelineTest, NotEqAnyWithAdditionalEqualitySameField) { pipeline = pipeline.AddingStage(std::make_shared(AndExpr( {NotEqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("diane")))), - EqExpr({std::make_shared("name"), - SharedConstant(Value("eric"))})}))); + EqualExpr({std::make_shared("name"), + SharedConstant(Value("eric"))})}))); // Expect docs where name is not alice/diane (doc2, doc3, doc5) AND name is // eric (doc5) @@ -1323,8 +1335,9 @@ TEST_F(DisjunctivePipelineTest, NotEqAnyWithInequalitiesExclusiveRange) { pipeline = pipeline.AddingStage(std::make_shared(AndExpr( {NotEqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("charlie")))), - GtExpr({std::make_shared("age"), SharedConstant(Value(10.0))}), - LtExpr( + GreaterThanExpr( + {std::make_shared("age"), SharedConstant(Value(10.0))}), + LessThanExpr( {std::make_shared("age"), SharedConstant(Value(100.0))})}))); // Expect docs where name is not alice/charlie (doc2, doc4, doc5) AND age > 10 @@ -1345,8 +1358,9 @@ TEST_F(DisjunctivePipelineTest, NotEqAnyWithInequalitiesInclusiveRange) { {NotEqAnyExpr( std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob"), Value("eric")))), - GteExpr({std::make_shared("age"), SharedConstant(Value(10.0))}), - LteExpr( + GreaterThanOrEqualExpr( + {std::make_shared("age"), SharedConstant(Value(10.0))}), + LessThanOrEqualExpr( {std::make_shared("age"), SharedConstant(Value(100.0))})}))); // Expect docs where name is not alice/bob/eric (doc3, doc4) AND age >= 10 AND @@ -1367,8 +1381,9 @@ TEST_F(DisjunctivePipelineTest, NotEqAnyWithInequalitiesAndSort) { pipeline = pipeline.AddingStage(std::make_shared(AndExpr( {NotEqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("diane")))), - GtExpr({std::make_shared("age"), SharedConstant(Value(10.0))}), - LteExpr( + GreaterThanExpr( + {std::make_shared("age"), SharedConstant(Value(10.0))}), + LessThanOrEqualExpr( {std::make_shared("age"), SharedConstant(Value(100.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( @@ -1391,7 +1406,7 @@ TEST_F(DisjunctivePipelineTest, NotEqAnyWithNotEqual) { pipeline = pipeline.AddingStage(std::make_shared(AndExpr( {NotEqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob")))), - NeqExpr( + NotEqualExpr( {std::make_shared("age"), SharedConstant(Value(100.0))})}))); // Expect docs where name is not alice/bob (doc3, doc4, doc5) AND age is not @@ -1451,7 +1466,7 @@ TEST_F(DisjunctivePipelineTest, NotEqAnyWithExtraEqualitySortOnNotEqAnyField) { pipeline = pipeline.AddingStage(std::make_shared(AndExpr( {NotEqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob")))), - EqExpr( + EqualExpr( {std::make_shared("age"), SharedConstant(Value(10.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( @@ -1474,7 +1489,7 @@ TEST_F(DisjunctivePipelineTest, NotEqAnyWithExtraEqualitySortOnEquality) { pipeline = pipeline.AddingStage(std::make_shared(AndExpr( {NotEqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("bob")))), - EqExpr( + EqualExpr( {std::make_shared("age"), SharedConstant(Value(10.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( @@ -1497,8 +1512,8 @@ TEST_F(DisjunctivePipelineTest, NotEqAnyWithInequalityOnSameField) { pipeline = pipeline.AddingStage(std::make_shared( AndExpr({NotEqAnyExpr(std::make_shared("age"), SharedConstant(Array(Value(10.0), Value(100.0)))), - GtExpr({std::make_shared("age"), - SharedConstant(Value(20.0))})}))); + GreaterThanExpr({std::make_shared("age"), + SharedConstant(Value(20.0))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("age"), Ordering::Direction::ASCENDING)})); @@ -1523,7 +1538,7 @@ TEST_F( pipeline = pipeline.AddingStage(std::make_shared(AndExpr( {NotEqAnyExpr(std::make_shared("name"), SharedConstant(Array(Value("alice"), Value("diane")))), - GtExpr( + GreaterThanExpr( {std::make_shared("age"), SharedConstant(Value(20.0))})}))); // Sort field is 'age', the inequality field. TS name was misleading. pipeline = pipeline.AddingStage( @@ -1550,26 +1565,28 @@ TEST_F(DisjunctivePipelineTest, NoLimitOnNumOfDisjunctions) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {EqExpr( + {EqualExpr( {std::make_shared("name"), SharedConstant(Value("alice"))}), - EqExpr({std::make_shared("name"), SharedConstant(Value("bob"))}), - EqExpr( + EqualExpr( + {std::make_shared("name"), SharedConstant(Value("bob"))}), + EqualExpr( {std::make_shared("name"), SharedConstant(Value("charlie"))}), - EqExpr( + EqualExpr( {std::make_shared("name"), SharedConstant(Value("diane"))}), - EqExpr({std::make_shared("age"), SharedConstant(Value(10.0))}), - EqExpr({std::make_shared("age"), SharedConstant(Value(25.0))}), - EqExpr({std::make_shared("age"), - SharedConstant(Value(40.0))}), // No doc matches this - EqExpr({std::make_shared("age"), SharedConstant(Value(100.0))}), - EqExpr( + EqualExpr({std::make_shared("age"), SharedConstant(Value(10.0))}), + EqualExpr({std::make_shared("age"), SharedConstant(Value(25.0))}), + EqualExpr({std::make_shared("age"), + SharedConstant(Value(40.0))}), // No doc matches this + EqualExpr( + {std::make_shared("age"), SharedConstant(Value(100.0))}), + EqualExpr( {std::make_shared("height"), SharedConstant(Value(150.0))}), - EqExpr({std::make_shared("height"), - SharedConstant(Value(160.0))}), // No doc matches this - EqExpr( + EqualExpr({std::make_shared("height"), + SharedConstant(Value(160.0))}), // No doc matches this + EqualExpr( {std::make_shared("height"), SharedConstant(Value(170.0))}), - EqExpr({std::make_shared("height"), - SharedConstant(Value(180.0))})}))); + EqualExpr({std::make_shared("height"), + SharedConstant(Value(180.0))})}))); // Since each doc matches at least one condition, all should be returned. EXPECT_THAT(RunPipeline(pipeline, documents), diff --git a/Firestore/core/test/unit/core/pipeline/error_handling_test.cc b/Firestore/core/test/unit/core/pipeline/error_handling_test.cc index 280749051c1..8db238e591f 100644 --- a/Firestore/core/test/unit/core/pipeline/error_handling_test.cc +++ b/Firestore/core/test/unit/core/pipeline/error_handling_test.cc @@ -68,16 +68,16 @@ using testutil::ArrayContainsAnyExpr; using testutil::ArrayContainsExpr; using testutil::DivideExpr; // Added for divide test using testutil::EqAnyExpr; -using testutil::EqExpr; -using testutil::GteExpr; -using testutil::GtExpr; +using testutil::EqualExpr; +using testutil::GreaterThanExpr; +using testutil::GreaterThanOrEqualExpr; using testutil::IsNanExpr; using testutil::IsNullExpr; +using testutil::LessThanExpr; +using testutil::LessThanOrEqualExpr; using testutil::LikeExpr; -using testutil::LteExpr; -using testutil::LtExpr; -using testutil::NeqExpr; using testutil::NotEqAnyExpr; +using testutil::NotEqualExpr; using testutil::NotExpr; using testutil::OrExpr; using testutil::XorExpr; @@ -123,16 +123,17 @@ TEST_F(ErrorHandlingPipelineTest, WherePartialErrorOr) { RealtimePipeline pipeline = StartPipeline("/k"); pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {EqExpr({std::make_shared("a"), - SharedConstant(Value(true))}), // Expects boolean true - EqExpr({std::make_shared("b"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("c"), SharedConstant(Value(true))})}))); + {EqualExpr({std::make_shared("a"), + SharedConstant(Value(true))}), // Expects boolean true + EqualExpr({std::make_shared("b"), SharedConstant(Value(true))}), + EqualExpr( + {std::make_shared("c"), SharedConstant(Value(true))})}))); // In Firestore, comparisons between different types are generally false. // The OR evaluates to true if *any* of the fields 'a', 'b', or 'c' is the // boolean value `true`. All documents have at least one field that is boolean // `true` or can be evaluated. Assuming type mismatches evaluate to false in - // EqExpr for OR. + // EqualExpr for OR. EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc1, doc2, doc3, doc4, doc5, doc6)); } @@ -164,12 +165,13 @@ TEST_F(ErrorHandlingPipelineTest, WherePartialErrorAnd) { RealtimePipeline pipeline = StartPipeline("k"); pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {EqExpr({std::make_shared("a"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("b"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("c"), SharedConstant(Value(true))})}))); + {EqualExpr({std::make_shared("a"), SharedConstant(Value(true))}), + EqualExpr({std::make_shared("b"), SharedConstant(Value(true))}), + EqualExpr( + {std::make_shared("c"), SharedConstant(Value(true))})}))); - // AND requires all conditions to be true. Type mismatches evaluate EqExpr to - // false. Only doc7 has a=true, b=true, AND c=true. + // AND requires all conditions to be true. Type mismatches evaluate EqualExpr + // to false. Only doc7 has a=true, b=true, AND c=true. EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc7)); } @@ -201,12 +203,13 @@ TEST_F(ErrorHandlingPipelineTest, WherePartialErrorXor) { RealtimePipeline pipeline = StartPipeline("k"); pipeline = pipeline.AddingStage(std::make_shared(XorExpr( - {// Casting might not work directly, using EqExpr for boolean check - EqExpr({std::make_shared("a"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("b"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("c"), SharedConstant(Value(true))})}))); + {// Casting might not work directly, using EqualExpr for boolean check + EqualExpr({std::make_shared("a"), SharedConstant(Value(true))}), + EqualExpr({std::make_shared("b"), SharedConstant(Value(true))}), + EqualExpr( + {std::make_shared("c"), SharedConstant(Value(true))})}))); - // Assuming type mismatches evaluate EqExpr to false: + // Assuming type mismatches evaluate EqualExpr to false: // doc1: F ^ T ^ F = T // doc2: T ^ F ^ F = T // doc3: T ^ F ^ F = T @@ -243,7 +246,7 @@ TEST_F(ErrorHandlingPipelineTest, WhereErrorProducingFunctionReturnsEmpty) { RealtimePipeline pipeline = StartPipeline("k"); // Division operation with string constants - this should likely cause an // evaluation error. - pipeline = pipeline.AddingStage(std::make_shared(EqExpr({ + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr({ DivideExpr({SharedConstant(Value("100")), SharedConstant(Value("50"))}), // Error here SharedConstant(Value(2LL)) // Comparing result to integer 2 diff --git a/Firestore/core/test/unit/core/pipeline/inequality_test.cc b/Firestore/core/test/unit/core/pipeline/inequality_test.cc index d3ede6de7af..ca00529072c 100644 --- a/Firestore/core/test/unit/core/pipeline/inequality_test.cc +++ b/Firestore/core/test/unit/core/pipeline/inequality_test.cc @@ -71,16 +71,16 @@ using testutil::ArrayContainsAnyExpr; using testutil::ArrayContainsExpr; using testutil::DivideExpr; using testutil::EqAnyExpr; -using testutil::EqExpr; -using testutil::GteExpr; -using testutil::GtExpr; +using testutil::EqualExpr; +using testutil::GreaterThanExpr; +using testutil::GreaterThanOrEqualExpr; using testutil::IsNanExpr; using testutil::IsNullExpr; +using testutil::LessThanExpr; +using testutil::LessThanOrEqualExpr; using testutil::LikeExpr; -using testutil::LteExpr; -using testutil::LtExpr; -using testutil::NeqExpr; using testutil::NotEqAnyExpr; +using testutil::NotEqualExpr; using testutil::NotExpr; using testutil::OrExpr; using testutil::XorExpr; @@ -103,8 +103,8 @@ TEST_F(InequalityPipelineTest, GreaterThan) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - GtExpr({std::make_shared("score"), SharedConstant(Value(90LL))}))); + pipeline = pipeline.AddingStage(std::make_shared(GreaterThanExpr( + {std::make_shared("score"), SharedConstant(Value(90LL))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc3)); } @@ -116,8 +116,9 @@ TEST_F(InequalityPipelineTest, GreaterThanOrEqual) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(GteExpr( - {std::make_shared("score"), SharedConstant(Value(90LL))}))); + pipeline = + pipeline.AddingStage(std::make_shared(GreaterThanOrEqualExpr( + {std::make_shared("score"), SharedConstant(Value(90LL))}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc1, doc3)); @@ -130,8 +131,8 @@ TEST_F(InequalityPipelineTest, LessThan) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - LtExpr({std::make_shared("score"), SharedConstant(Value(90LL))}))); + pipeline = pipeline.AddingStage(std::make_shared(LessThanExpr( + {std::make_shared("score"), SharedConstant(Value(90LL))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc2)); } @@ -143,7 +144,7 @@ TEST_F(InequalityPipelineTest, LessThanOrEqual) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(LteExpr( + pipeline = pipeline.AddingStage(std::make_shared(LessThanOrEqualExpr( {std::make_shared("score"), SharedConstant(Value(90LL))}))); EXPECT_THAT(RunPipeline(pipeline, documents), @@ -157,7 +158,7 @@ TEST_F(InequalityPipelineTest, NotEqual) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(NeqExpr( + pipeline = pipeline.AddingStage(std::make_shared(NotEqualExpr( {std::make_shared("score"), SharedConstant(Value(90LL))}))); EXPECT_THAT(RunPipeline(pipeline, documents), @@ -187,7 +188,7 @@ TEST_F(InequalityPipelineTest, NotEqualReturnsMixedTypes) { doc5, doc6, doc7, doc8}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(NeqExpr( + pipeline = pipeline.AddingStage(std::make_shared(NotEqualExpr( {std::make_shared("score"), SharedConstant(Value(90LL))}))); // Neq returns true for different types. @@ -212,8 +213,8 @@ TEST_F(InequalityPipelineTest, ComparisonHasImplicitBound) { doc5, doc6, doc7, doc8}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - GtExpr({std::make_shared("score"), SharedConstant(Value(42LL))}))); + pipeline = pipeline.AddingStage(std::make_shared(GreaterThanExpr( + {std::make_shared("score"), SharedConstant(Value(42LL))}))); // Only numeric types greater than 42 are matched. EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc2)); @@ -248,11 +249,12 @@ TEST_F(InequalityPipelineTest, NotComparisonReturnsMixedType) { doc5, doc6, doc7, doc8}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(NotExpr(GtExpr( - {std::make_shared("score"), SharedConstant(Value(90LL))})))); + pipeline = + pipeline.AddingStage(std::make_shared(NotExpr(GreaterThanExpr( + {std::make_shared("score"), SharedConstant(Value(90LL))})))); // NOT (score > 90). Comparison is only true for score=100.0. NOT flips it. - // Type mismatches result in false for GtExpr, NOT flips to true. + // Type mismatches result in false for GreaterThanExpr, NOT flips to true. EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc1, doc3, doc4, doc5, doc6, doc7, doc8)); } @@ -269,8 +271,8 @@ TEST_F(InequalityPipelineTest, InequalityWithEqualityOnDifferentField) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {EqExpr({std::make_shared("rank"), SharedConstant(Value(2LL))}), - GtExpr( + {EqualExpr({std::make_shared("rank"), SharedConstant(Value(2LL))}), + GreaterThanExpr( {std::make_shared("score"), SharedConstant(Value(80LL))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc1)); @@ -284,10 +286,11 @@ TEST_F(InequalityPipelineTest, InequalityWithEqualityOnSameField) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {EqExpr({std::make_shared("score"), SharedConstant(Value(90LL))}), - GtExpr( - {std::make_shared("score"), SharedConstant(Value(80LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({EqualExpr({std::make_shared("score"), + SharedConstant(Value(90LL))}), + GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(80LL))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc1)); } @@ -299,8 +302,9 @@ TEST_F(InequalityPipelineTest, WithSortOnSameField) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(GteExpr( - {std::make_shared("score"), SharedConstant(Value(90LL))}))); + pipeline = + pipeline.AddingStage(std::make_shared(GreaterThanOrEqualExpr( + {std::make_shared("score"), SharedConstant(Value(90LL))}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("score"), Ordering::Direction::ASCENDING)})); @@ -316,8 +320,9 @@ TEST_F(InequalityPipelineTest, WithSortOnDifferentFields) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(GteExpr( - {std::make_shared("score"), SharedConstant(Value(90LL))}))); + pipeline = + pipeline.AddingStage(std::make_shared(GreaterThanOrEqualExpr( + {std::make_shared("score"), SharedConstant(Value(90LL))}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("rank"), Ordering::Direction::ASCENDING)})); @@ -335,10 +340,11 @@ TEST_F(InequalityPipelineTest, WithOrOnSingleField) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {GtExpr({std::make_shared("score"), SharedConstant(Value(90LL))}), - LtExpr( - {std::make_shared("score"), SharedConstant(Value(60LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + OrExpr({GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(90LL))}), + LessThanExpr({std::make_shared("score"), + SharedConstant(Value(60LL))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc2, doc3)); @@ -355,10 +361,11 @@ TEST_F(InequalityPipelineTest, WithOrOnDifferentFields) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {GtExpr({std::make_shared("score"), SharedConstant(Value(80LL))}), - LtExpr( - {std::make_shared("rank"), SharedConstant(Value(2LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + OrExpr({GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(80LL))}), + LessThanExpr({std::make_shared("rank"), + SharedConstant(Value(2LL))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc1, doc3)); @@ -375,7 +382,8 @@ TEST_F(InequalityPipelineTest, WithEqAnyOnSingleField) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {GtExpr({std::make_shared("score"), SharedConstant(Value(80LL))}), + {GreaterThanExpr( + {std::make_shared("score"), SharedConstant(Value(80LL))}), EqAnyExpr( std::make_shared("score"), SharedConstant(Array(Value(50LL), Value(80LL), Value(97LL))))}))); @@ -396,7 +404,8 @@ TEST_F(InequalityPipelineTest, WithEqAnyOnDifferentFields) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {LtExpr({std::make_shared("rank"), SharedConstant(Value(3LL))}), + {LessThanExpr( + {std::make_shared("rank"), SharedConstant(Value(3LL))}), EqAnyExpr( std::make_shared("score"), SharedConstant(Array(Value(50LL), Value(80LL), Value(97LL))))}))); @@ -415,7 +424,8 @@ TEST_F(InequalityPipelineTest, WithNotEqAnyOnSingleField) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {GtExpr({std::make_shared("score"), SharedConstant(Value(80LL))}), + {GreaterThanExpr( + {std::make_shared("score"), SharedConstant(Value(80LL))}), NotEqAnyExpr(std::make_shared("score"), SharedConstant(Array(Value(90LL), Value(95LL))))}))); @@ -488,7 +498,8 @@ TEST_F(InequalityPipelineTest, WithNotEqAnyOnDifferentFields) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {LtExpr({std::make_shared("rank"), SharedConstant(Value(3LL))}), + {LessThanExpr( + {std::make_shared("rank"), SharedConstant(Value(3LL))}), NotEqAnyExpr(std::make_shared("score"), SharedConstant(Array(Value(90LL), Value(95LL))))}))); @@ -510,8 +521,8 @@ TEST_F(InequalityPipelineTest, SortByEquality) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {EqExpr({std::make_shared("rank"), SharedConstant(Value(2LL))}), - GtExpr( + {EqualExpr({std::make_shared("rank"), SharedConstant(Value(2LL))}), + GreaterThanExpr( {std::make_shared("score"), SharedConstant(Value(80LL))})}))); pipeline = pipeline.AddingStage(std::make_shared( std::vector{Ordering(std::make_unique("rank"), @@ -539,7 +550,7 @@ TEST_F(InequalityPipelineTest, WithEqAnySortByEquality) { pipeline = pipeline.AddingStage(std::make_shared(AndExpr( {EqAnyExpr(std::make_shared("rank"), SharedConstant(Array(Value(2LL), Value(3LL), Value(4LL)))), - GtExpr( + GreaterThanExpr( {std::make_shared("score"), SharedConstant(Value(80LL))})}))); pipeline = pipeline.AddingStage(std::make_shared( std::vector{Ordering(std::make_unique("rank"), @@ -567,10 +578,11 @@ TEST_F(InequalityPipelineTest, WithArray) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {LteExpr({std::make_shared("scores"), - SharedConstant(Array(Value(90LL), Value(90LL), Value(90LL)))}), - GtExpr({std::make_shared("rounds"), - SharedConstant(Array(Value(1LL), Value(2LL)))})}))); + {LessThanOrEqualExpr( + {std::make_shared("scores"), + SharedConstant(Array(Value(90LL), Value(90LL), Value(90LL)))}), + GreaterThanExpr({std::make_shared("rounds"), + SharedConstant(Array(Value(1LL), Value(2LL)))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc1)); } @@ -597,8 +609,9 @@ TEST_F(InequalityPipelineTest, RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared(AndExpr({ - LteExpr({std::make_shared("scores"), - SharedConstant(Array(Value(90LL), Value(90LL), Value(90LL)))}), + LessThanOrEqualExpr( + {std::make_shared("scores"), + SharedConstant(Array(Value(90LL), Value(90LL), Value(90LL)))}), ArrayContainsExpr( {std::make_shared("rounds"), SharedConstant(Value(3LL))}) // TS used ArrayContains here @@ -616,8 +629,8 @@ TEST_F(InequalityPipelineTest, WithSortAndLimit) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - GtExpr({std::make_shared("score"), SharedConstant(Value(80LL))}))); + pipeline = pipeline.AddingStage(std::make_shared(GreaterThanExpr( + {std::make_shared("score"), SharedConstant(Value(80LL))}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("rank"), Ordering::Direction::ASCENDING)})); @@ -636,10 +649,11 @@ TEST_F(InequalityPipelineTest, MultipleInequalitiesOnSingleField) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {GtExpr({std::make_shared("score"), SharedConstant(Value(90LL))}), - LtExpr({std::make_shared("score"), - SharedConstant(Value(100LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(90LL))}), + LessThanExpr({std::make_shared("score"), + SharedConstant(Value(100LL))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc3)); } @@ -656,10 +670,11 @@ TEST_F(InequalityPipelineTest, PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {GtExpr({std::make_shared("score"), SharedConstant(Value(90LL))}), - LtExpr( - {std::make_shared("rank"), SharedConstant(Value(2LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(90LL))}), + LessThanExpr({std::make_shared("rank"), + SharedConstant(Value(2LL))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc3)); } @@ -677,10 +692,11 @@ TEST_F(InequalityPipelineTest, PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {GtExpr({std::make_shared("score"), SharedConstant(Value(80LL))}), - LtExpr( - {std::make_shared("rank"), SharedConstant(Value(3LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(80LL))}), + LessThanExpr({std::make_shared("rank"), + SharedConstant(Value(3LL))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc1, doc3)); @@ -699,10 +715,11 @@ TEST_F(InequalityPipelineTest, MultipleInequalitiesOnDifferentFieldsAllMatch) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {GtExpr({std::make_shared("score"), SharedConstant(Value(40LL))}), - LtExpr( - {std::make_shared("rank"), SharedConstant(Value(4LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(40LL))}), + LessThanExpr({std::make_shared("rank"), + SharedConstant(Value(4LL))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc1, doc2, doc3)); @@ -718,10 +735,11 @@ TEST_F(InequalityPipelineTest, MultipleInequalitiesOnDifferentFieldsNoMatch) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {LtExpr({std::make_shared("score"), SharedConstant(Value(90LL))}), - GtExpr( - {std::make_shared("rank"), SharedConstant(Value(3LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({LessThanExpr({std::make_shared("score"), + SharedConstant(Value(90LL))}), + GreaterThanExpr({std::make_shared("rank"), + SharedConstant(Value(3LL))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } @@ -739,12 +757,15 @@ TEST_F(InequalityPipelineTest, MultipleInequalitiesWithBoundedRanges) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {GtExpr({std::make_shared("rank"), SharedConstant(Value(0LL))}), - LtExpr({std::make_shared("rank"), SharedConstant(Value(4LL))}), - GtExpr({std::make_shared("score"), SharedConstant(Value(80LL))}), - LtExpr( - {std::make_shared("score"), SharedConstant(Value(95LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({GreaterThanExpr({std::make_shared("rank"), + SharedConstant(Value(0LL))}), + LessThanExpr({std::make_shared("rank"), + SharedConstant(Value(4LL))}), + GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(80LL))}), + LessThanExpr({std::make_shared("score"), + SharedConstant(Value(95LL))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc1)); } @@ -758,10 +779,11 @@ TEST_F(InequalityPipelineTest, MultipleInequalitiesWithSingleSortAsc) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {LtExpr({std::make_shared("rank"), SharedConstant(Value(3LL))}), - GtExpr( - {std::make_shared("score"), SharedConstant(Value(80LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({LessThanExpr({std::make_shared("rank"), + SharedConstant(Value(3LL))}), + GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(80LL))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("rank"), Ordering::Direction::ASCENDING)})); @@ -778,10 +800,11 @@ TEST_F(InequalityPipelineTest, MultipleInequalitiesWithSingleSortDesc) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {LtExpr({std::make_shared("rank"), SharedConstant(Value(3LL))}), - GtExpr( - {std::make_shared("score"), SharedConstant(Value(80LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({LessThanExpr({std::make_shared("rank"), + SharedConstant(Value(3LL))}), + GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(80LL))})}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("rank"), Ordering::Direction::DESCENDING)})); @@ -798,10 +821,11 @@ TEST_F(InequalityPipelineTest, MultipleInequalitiesWithMultipleSortAsc) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {LtExpr({std::make_shared("rank"), SharedConstant(Value(3LL))}), - GtExpr( - {std::make_shared("score"), SharedConstant(Value(80LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({LessThanExpr({std::make_shared("rank"), + SharedConstant(Value(3LL))}), + GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(80LL))})}))); pipeline = pipeline.AddingStage(std::make_shared( std::vector{Ordering(std::make_unique("rank"), Ordering::Direction::ASCENDING), @@ -820,10 +844,11 @@ TEST_F(InequalityPipelineTest, MultipleInequalitiesWithMultipleSortDesc) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {LtExpr({std::make_shared("rank"), SharedConstant(Value(3LL))}), - GtExpr( - {std::make_shared("score"), SharedConstant(Value(80LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({LessThanExpr({std::make_shared("rank"), + SharedConstant(Value(3LL))}), + GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(80LL))})}))); pipeline = pipeline.AddingStage(std::make_shared( std::vector{Ordering(std::make_unique("rank"), Ordering::Direction::DESCENDING), @@ -843,10 +868,11 @@ TEST_F(InequalityPipelineTest, PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {LtExpr({std::make_shared("rank"), SharedConstant(Value(3LL))}), - GtExpr( - {std::make_shared("score"), SharedConstant(Value(80LL))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({LessThanExpr({std::make_shared("rank"), + SharedConstant(Value(3LL))}), + GreaterThanExpr({std::make_shared("score"), + SharedConstant(Value(80LL))})}))); pipeline = pipeline.AddingStage(std::make_shared( std::vector{Ordering(std::make_unique("score"), Ordering::Direction::DESCENDING), diff --git a/Firestore/core/test/unit/core/pipeline/nested_properties_test.cc b/Firestore/core/test/unit/core/pipeline/nested_properties_test.cc index 84b2197c725..bdeaf3fa51f 100644 --- a/Firestore/core/test/unit/core/pipeline/nested_properties_test.cc +++ b/Firestore/core/test/unit/core/pipeline/nested_properties_test.cc @@ -66,13 +66,13 @@ using testutil::Map; using testutil::SharedConstant; using testutil::Value; // Expression helpers -using testutil::EqExpr; +using testutil::EqualExpr; using testutil::ExistsExpr; -using testutil::GteExpr; -using testutil::GtExpr; +using testutil::GreaterThanExpr; +using testutil::GreaterThanOrEqualExpr; using testutil::IsNullExpr; -using testutil::LtExpr; -using testutil::NeqExpr; +using testutil::LessThanExpr; +using testutil::NotEqualExpr; using testutil::NotExpr; // Test Fixture for Nested Properties Pipeline tests @@ -129,8 +129,8 @@ TEST_F(NestedPropertiesPipelineTest, WhereEqualityDeeplyNested) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("a.b.c.d.e.f.g.h.i.j.k"), - SharedConstant(Value(42LL))}))); + EqualExpr({std::make_shared("a.b.c.d.e.f.g.h.i.j.k"), + SharedConstant(Value(42LL))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc1)); } @@ -180,8 +180,8 @@ TEST_F(NestedPropertiesPipelineTest, WhereInequalityDeeplyNested) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared( - GteExpr({std::make_shared("a.b.c.d.e.f.g.h.i.j.k"), - SharedConstant(Value(0LL))}))); + GreaterThanOrEqualExpr({std::make_shared("a.b.c.d.e.f.g.h.i.j.k"), + SharedConstant(Value(0LL))}))); pipeline = pipeline.AddingStage(std::make_shared(std::vector{ Ordering(std::make_unique(FieldPath::kDocumentKeyPath), @@ -205,9 +205,9 @@ TEST_F(NestedPropertiesPipelineTest, WhereEquality) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage( - std::make_shared(EqExpr({std::make_shared("address.street"), - SharedConstant(Value("76"))}))); + pipeline = pipeline.AddingStage(std::make_shared( + EqualExpr({std::make_shared("address.street"), + SharedConstant(Value("76"))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc2)); } @@ -227,11 +227,11 @@ TEST_F(NestedPropertiesPipelineTest, MultipleFilters) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("address.city"), - SharedConstant(Value("San Francisco"))}))); - pipeline = pipeline.AddingStage( - std::make_shared(GtExpr({std::make_shared("address.zip"), - SharedConstant(Value(90000LL))}))); + EqualExpr({std::make_shared("address.city"), + SharedConstant(Value("San Francisco"))}))); + pipeline = pipeline.AddingStage(std::make_shared( + GreaterThanExpr({std::make_shared("address.zip"), + SharedConstant(Value(90000LL))}))); // city == "San Francisco" AND zip > 90000 // doc1: T AND 94105 > 90000 (T) -> True @@ -255,13 +255,13 @@ TEST_F(NestedPropertiesPipelineTest, MultipleFiltersRedundant) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline = StartPipeline("/users"); + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("address"), + SharedConstant(Map( // Use testutil::Map helper + "city", "San Francisco", "state", "CA", "zip", 94105LL))}))); pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("address"), - SharedConstant(Map( // Use testutil::Map helper - "city", "San Francisco", "state", "CA", "zip", 94105LL))}))); - pipeline = pipeline.AddingStage( - std::make_shared(GtExpr({std::make_shared("address.zip"), - SharedConstant(Value(90000LL))}))); + GreaterThanExpr({std::make_shared("address.zip"), + SharedConstant(Value(90000LL))}))); // address == {city: SF, state: CA, zip: 94105} AND address.zip > 90000 // doc1: T AND 94105 > 90000 (T) -> True @@ -288,11 +288,11 @@ TEST_F(NestedPropertiesPipelineTest, MultipleFiltersWithCompositeIndex) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("address.city"), - SharedConstant(Value("San Francisco"))}))); - pipeline = pipeline.AddingStage( - std::make_shared(GtExpr({std::make_shared("address.zip"), - SharedConstant(Value(90000LL))}))); + EqualExpr({std::make_shared("address.city"), + SharedConstant(Value("San Francisco"))}))); + pipeline = pipeline.AddingStage(std::make_shared( + GreaterThanExpr({std::make_shared("address.zip"), + SharedConstant(Value(90000LL))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc1)); } @@ -314,26 +314,26 @@ TEST_F(NestedPropertiesPipelineTest, WhereInequality) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4}; RealtimePipeline pipeline1 = StartPipeline("/users"); - pipeline1 = pipeline1.AddingStage( - std::make_shared(GtExpr({std::make_shared("address.zip"), - SharedConstant(Value(90000LL))}))); + pipeline1 = pipeline1.AddingStage(std::make_shared( + GreaterThanExpr({std::make_shared("address.zip"), + SharedConstant(Value(90000LL))}))); EXPECT_THAT(RunPipeline(pipeline1, documents), ElementsAre(doc1, doc3)); RealtimePipeline pipeline2 = StartPipeline("/users"); - pipeline2 = pipeline2.AddingStage( - std::make_shared(LtExpr({std::make_shared("address.zip"), - SharedConstant(Value(90000LL))}))); + pipeline2 = pipeline2.AddingStage(std::make_shared( + LessThanExpr({std::make_shared("address.zip"), + SharedConstant(Value(90000LL))}))); EXPECT_THAT(RunPipeline(pipeline2, documents), ElementsAre(doc2)); RealtimePipeline pipeline3 = StartPipeline("/users"); - pipeline3 = pipeline3.AddingStage(std::make_shared(LtExpr( + pipeline3 = pipeline3.AddingStage(std::make_shared(LessThanExpr( {std::make_shared("address.zip"), SharedConstant(Value(0LL))}))); EXPECT_THAT(RunPipeline(pipeline3, documents), IsEmpty()); RealtimePipeline pipeline4 = StartPipeline("/users"); - pipeline4 = pipeline4.AddingStage( - std::make_shared(NeqExpr({std::make_shared("address.zip"), - SharedConstant(Value(10011LL))}))); + pipeline4 = pipeline4.AddingStage(std::make_shared( + NotEqualExpr({std::make_shared("address.zip"), + SharedConstant(Value(10011LL))}))); EXPECT_THAT(RunPipeline(pipeline4, documents), ElementsAre(doc1, doc3)); } @@ -474,8 +474,8 @@ TEST_F(NestedPropertiesPipelineTest, QuotedNestedPropertyFilterNested) { RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("address.city"), - SharedConstant(Value("San Francisco"))}))); + EqualExpr({std::make_shared("address.city"), + SharedConstant(Value("San Francisco"))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc2)); } @@ -491,8 +491,8 @@ TEST_F(NestedPropertiesPipelineTest, QuotedNestedPropertyFilterQuotedNested) { RealtimePipeline pipeline = StartPipeline("/users"); // Use FieldPath constructor for field names containing dots pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared(FieldPath({"address.city"})), - SharedConstant(Value("San Francisco"))}))); + EqualExpr({std::make_shared(FieldPath({"address.city"})), + SharedConstant(Value("San Francisco"))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc1)); } diff --git a/Firestore/core/test/unit/core/pipeline/null_semantics_test.cc b/Firestore/core/test/unit/core/pipeline/null_semantics_test.cc index c04d0a9594e..d55e1e3d12c 100644 --- a/Firestore/core/test/unit/core/pipeline/null_semantics_test.cc +++ b/Firestore/core/test/unit/core/pipeline/null_semantics_test.cc @@ -66,16 +66,16 @@ using testutil::ArrayContainsAllExpr; using testutil::ArrayContainsAnyExpr; using testutil::ArrayContainsExpr; using testutil::EqAnyExpr; -using testutil::EqExpr; -using testutil::GteExpr; -using testutil::GtExpr; +using testutil::EqualExpr; +using testutil::GreaterThanExpr; +using testutil::GreaterThanOrEqualExpr; using testutil::IsErrorExpr; // Add using for IsErrorExpr using testutil::IsNanExpr; using testutil::IsNullExpr; -using testutil::LteExpr; -using testutil::LtExpr; -using testutil::NeqExpr; +using testutil::LessThanExpr; +using testutil::LessThanOrEqualExpr; using testutil::NotEqAnyExpr; +using testutil::NotEqualExpr; using testutil::NotExpr; using testutil::OrExpr; using testutil::XorExpr; @@ -166,7 +166,7 @@ TEST_F(NullSemanticsPipelineTest, WhereEqConstantAsNull) { RealtimePipeline pipeline = StartPipeline("/users"); // Equality filters never match null or missing fields. - pipeline = pipeline.AddingStage(std::make_shared(EqExpr( + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( {std::make_shared("score"), SharedConstant(Value(nullptr))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); @@ -183,7 +183,7 @@ TEST_F(NullSemanticsPipelineTest, WhereEqFieldAsNull) { RealtimePipeline pipeline = StartPipeline("/users"); // Equality filters never match null or missing fields, even against other // fields. - pipeline = pipeline.AddingStage(std::make_shared(EqExpr( + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( {std::make_shared("score"), std::make_shared("rank")}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); @@ -203,8 +203,8 @@ TEST_F(NullSemanticsPipelineTest, WhereEqSegmentField) { RealtimePipeline pipeline = StartPipeline("/users"); // Equality filters never match null or missing fields. pipeline = pipeline.AddingStage( - std::make_shared(EqExpr({std::make_shared("score.bonus"), - SharedConstant(Value(nullptr))}))); + std::make_shared(EqualExpr({std::make_shared("score.bonus"), + SharedConstant(Value(nullptr))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } @@ -228,10 +228,10 @@ TEST_F(NullSemanticsPipelineTest, WhereEqSingleFieldAndSegmentField) { RealtimePipeline pipeline = StartPipeline("/users"); // Equality filters never match null or missing fields. pipeline = pipeline.AddingStage(std::make_shared( - AndExpr({EqExpr({std::make_shared("score.bonus"), - SharedConstant(Value(nullptr))}), - EqExpr({std::make_shared("rank"), - SharedConstant(Value(nullptr))})}))); + AndExpr({EqualExpr({std::make_shared("score.bonus"), + SharedConstant(Value(nullptr))}), + EqualExpr({std::make_shared("rank"), + SharedConstant(Value(nullptr))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } @@ -250,8 +250,8 @@ TEST_F(NullSemanticsPipelineTest, WhereEqNullInArray) { RealtimePipeline pipeline = StartPipeline("/k"); // Equality filters never match null values, even within arrays. pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("foo"), - SharedConstant(Value(Array(Value(nullptr))))}))); + EqualExpr({std::make_shared("foo"), + SharedConstant(Value(Array(Value(nullptr))))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } @@ -275,8 +275,8 @@ TEST_F(NullSemanticsPipelineTest, WhereEqNullOtherInArray) { RealtimePipeline pipeline = StartPipeline("/k"); // Equality filters never match null values, even within arrays. pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("foo"), - SharedConstant(Value(Array(Value(1.0), Value(nullptr))))}))); + EqualExpr({std::make_shared("foo"), + SharedConstant(Value(Array(Value(1.0), Value(nullptr))))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } @@ -294,11 +294,11 @@ TEST_F(NullSemanticsPipelineTest, WhereEqNullNanInArray) { RealtimePipeline pipeline = StartPipeline("/k"); // Equality filters never match null or NaN values, even within arrays. - pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("foo"), - SharedConstant(Value( - Array(Value(nullptr), - Value(std::numeric_limits::quiet_NaN()))))}))); + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("foo"), + SharedConstant( + Value(Array(Value(nullptr), + Value(std::numeric_limits::quiet_NaN()))))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } @@ -313,7 +313,7 @@ TEST_F(NullSemanticsPipelineTest, WhereEqNullInMap) { RealtimePipeline pipeline = StartPipeline("/k"); // Equality filters never match null values, even within maps. - pipeline = pipeline.AddingStage(std::make_shared(EqExpr( + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( {std::make_shared("foo"), SharedConstant(Map("a", nullptr))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); @@ -333,8 +333,8 @@ TEST_F(NullSemanticsPipelineTest, WhereEqNullOtherInMap) { RealtimePipeline pipeline = StartPipeline("/k"); // Equality filters never match null values, even within maps. pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("foo"), - SharedConstant(Map("a", 1.0, "b", nullptr))}))); + EqualExpr({std::make_shared("foo"), + SharedConstant(Map("a", 1.0, "b", nullptr))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } @@ -349,10 +349,10 @@ TEST_F(NullSemanticsPipelineTest, WhereEqNullNanInMap) { RealtimePipeline pipeline = StartPipeline("/k"); // Equality filters never match null or NaN values, even within maps. - pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("foo"), - SharedConstant(Map("a", nullptr, "b", - std::numeric_limits::quiet_NaN()))}))); + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("foo"), + SharedConstant(Map("a", nullptr, "b", + std::numeric_limits::quiet_NaN()))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } @@ -382,8 +382,8 @@ TEST_F(NullSemanticsPipelineTest, WhereEqMapWithNullArray) { RealtimePipeline pipeline = StartPipeline("/k"); // Equality filters never match null values, even within nested arrays/maps. pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("foo"), - SharedConstant(Map("a", Value(Array(Value(nullptr)))))}))); + EqualExpr({std::make_shared("foo"), + SharedConstant(Map("a", Value(Array(Value(nullptr)))))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } @@ -417,7 +417,7 @@ TEST_F(NullSemanticsPipelineTest, WhereEqMapWithNullOtherArray) { RealtimePipeline pipeline = StartPipeline("/k"); // Equality filters never match null values, even within nested arrays/maps. - pipeline = pipeline.AddingStage(std::make_shared(EqExpr( + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( {std::make_shared("foo"), SharedConstant(Map("a", Value(Array(Value(1.0), Value(nullptr)))))}))); @@ -449,7 +449,7 @@ TEST_F(NullSemanticsPipelineTest, WhereEqMapWithNullNanArray) { RealtimePipeline pipeline = StartPipeline("/k"); // Equality filters never match null or NaN values, even within nested // arrays/maps. - pipeline = pipeline.AddingStage(std::make_shared(EqExpr( + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( {std::make_shared("foo"), SharedConstant(Map( "a", @@ -466,10 +466,11 @@ TEST_F(NullSemanticsPipelineTest, WhereCompositeConditionWithNull) { RealtimePipeline pipeline = StartPipeline("/users"); // Equality filters never match null values. - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {EqExpr({std::make_shared("score"), SharedConstant(Value(42LL))}), - EqExpr({std::make_shared("rank"), - SharedConstant(Value(nullptr))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({EqualExpr({std::make_shared("score"), + SharedConstant(Value(42LL))}), + EqualExpr({std::make_shared("rank"), + SharedConstant(Value(nullptr))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } @@ -660,7 +661,7 @@ TEST_F(NullSemanticsPipelineTest, WhereNeqConstantAsNull) { RealtimePipeline pipeline = StartPipeline("/users"); // != null is not a supported query. - pipeline = pipeline.AddingStage(std::make_shared(NeqExpr( + pipeline = pipeline.AddingStage(std::make_shared(NotEqualExpr( {std::make_shared("score"), SharedConstant(Value(nullptr))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); @@ -676,7 +677,7 @@ TEST_F(NullSemanticsPipelineTest, WhereNeqFieldAsNull) { RealtimePipeline pipeline = StartPipeline("/users"); // != null is not a supported query, even against fields. - pipeline = pipeline.AddingStage(std::make_shared(NeqExpr( + pipeline = pipeline.AddingStage(std::make_shared(NotEqualExpr( {std::make_shared("score"), std::make_shared("rank")}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); @@ -696,8 +697,8 @@ TEST_F(NullSemanticsPipelineTest, WhereNeqNullInArray) { RealtimePipeline pipeline = StartPipeline("/k"); // != [null] is not a supported query. pipeline = pipeline.AddingStage(std::make_shared( - NeqExpr({std::make_shared("foo"), - SharedConstant(Value(Array(Value(nullptr))))}))); + NotEqualExpr({std::make_shared("foo"), + SharedConstant(Value(Array(Value(nullptr))))}))); // Based on TS result, this seems to match documents where 'foo' is not // exactly `[null]`. This behavior might differ in C++ SDK. Assuming it @@ -723,9 +724,9 @@ TEST_F(NullSemanticsPipelineTest, WhereNeqNullOtherInArray) { RealtimePipeline pipeline = StartPipeline("/k"); // != [1.0, null] is not a supported query. - pipeline = pipeline.AddingStage(std::make_shared( - NeqExpr({std::make_shared("foo"), - SharedConstant(Value(Array(Value(1.0), Value(nullptr))))}))); + pipeline = pipeline.AddingStage(std::make_shared(NotEqualExpr( + {std::make_shared("foo"), + SharedConstant(Value(Array(Value(1.0), Value(nullptr))))}))); // Based on TS result. EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc1)); @@ -744,11 +745,11 @@ TEST_F(NullSemanticsPipelineTest, WhereNeqNullNanInArray) { RealtimePipeline pipeline = StartPipeline("/k"); // != [null, NaN] is not a supported query. - pipeline = pipeline.AddingStage(std::make_shared( - NeqExpr({std::make_shared("foo"), - SharedConstant(Value( - Array(Value(nullptr), - Value(std::numeric_limits::quiet_NaN()))))}))); + pipeline = pipeline.AddingStage(std::make_shared(NotEqualExpr( + {std::make_shared("foo"), + SharedConstant( + Value(Array(Value(nullptr), + Value(std::numeric_limits::quiet_NaN()))))}))); // Based on TS result. EXPECT_THAT( @@ -775,7 +776,7 @@ TEST_F(NullSemanticsPipelineTest, WhereNeqNullInMap) { RealtimePipeline pipeline = StartPipeline("/k"); // != {a: null} is not a supported query. - pipeline = pipeline.AddingStage(std::make_shared(NeqExpr( + pipeline = pipeline.AddingStage(std::make_shared(NotEqualExpr( {std::make_shared("foo"), SharedConstant(Map("a", nullptr))}))); // Based on TS result. @@ -797,8 +798,8 @@ TEST_F(NullSemanticsPipelineTest, WhereNeqNullOtherInMap) { RealtimePipeline pipeline = StartPipeline("/k"); // != {a: 1.0, b: null} is not a supported query. pipeline = pipeline.AddingStage(std::make_shared( - NeqExpr({std::make_shared("foo"), - SharedConstant(Map("a", 1.0, "b", nullptr))}))); + NotEqualExpr({std::make_shared("foo"), + SharedConstant(Map("a", 1.0, "b", nullptr))}))); // Based on TS result. EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc1)); @@ -814,7 +815,7 @@ TEST_F(NullSemanticsPipelineTest, WhereNeqNullNanInMap) { RealtimePipeline pipeline = StartPipeline("/k"); // != {a: null, b: NaN} is not a supported query. - pipeline = pipeline.AddingStage(std::make_shared(NeqExpr( + pipeline = pipeline.AddingStage(std::make_shared(NotEqualExpr( {std::make_shared("foo"), SharedConstant(Map("a", nullptr, "b", std::numeric_limits::quiet_NaN()))}))); @@ -858,7 +859,7 @@ TEST_F(NullSemanticsPipelineTest, WhereGt) { RealtimePipeline pipeline = StartPipeline("users"); // > null is not supported. - pipeline = pipeline.AddingStage(std::make_shared(GtExpr( + pipeline = pipeline.AddingStage(std::make_shared(GreaterThanExpr( {std::make_shared("score"), SharedConstant(Value(nullptr))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); @@ -875,8 +876,9 @@ TEST_F(NullSemanticsPipelineTest, WhereGte) { RealtimePipeline pipeline = StartPipeline("users"); // >= null is not supported. - pipeline = pipeline.AddingStage(std::make_shared(GteExpr( - {std::make_shared("score"), SharedConstant(Value(nullptr))}))); + pipeline = + pipeline.AddingStage(std::make_shared(GreaterThanOrEqualExpr( + {std::make_shared("score"), SharedConstant(Value(nullptr))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } @@ -892,7 +894,7 @@ TEST_F(NullSemanticsPipelineTest, WhereLt) { RealtimePipeline pipeline = StartPipeline("users"); // < null is not supported. - pipeline = pipeline.AddingStage(std::make_shared(LtExpr( + pipeline = pipeline.AddingStage(std::make_shared(LessThanExpr( {std::make_shared("score"), SharedConstant(Value(nullptr))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); @@ -909,7 +911,7 @@ TEST_F(NullSemanticsPipelineTest, WhereLte) { RealtimePipeline pipeline = StartPipeline("users"); // <= null is not supported. - pipeline = pipeline.AddingStage(std::make_shared(LteExpr( + pipeline = pipeline.AddingStage(std::make_shared(LessThanOrEqualExpr( {std::make_shared("score"), SharedConstant(Value(nullptr))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); @@ -930,8 +932,9 @@ TEST_F(NullSemanticsPipelineTest, WhereAnd) { RealtimePipeline pipeline = StartPipeline("k"); // Need explicit boolean comparison pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {EqExpr({std::make_shared("a"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("b"), SharedConstant(Value(true))})}))); + {EqualExpr({std::make_shared("a"), SharedConstant(Value(true))}), + EqualExpr( + {std::make_shared("b"), SharedConstant(Value(true))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc4)); } @@ -951,8 +954,9 @@ TEST_F(NullSemanticsPipelineTest, WhereIsNullAnd) { RealtimePipeline pipeline = StartPipeline("k"); // Need explicit boolean comparison pipeline = pipeline.AddingStage(std::make_shared(IsNullExpr(AndExpr( - {EqExpr({std::make_shared("a"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("b"), SharedConstant(Value(true))})})))); + {EqualExpr({std::make_shared("a"), SharedConstant(Value(true))}), + EqualExpr( + {std::make_shared("b"), SharedConstant(Value(true))})})))); // Expect docs where (a==true AND b==true) evaluates to NULL. // This happens if either a or b is null/missing AND the other is not false. @@ -998,9 +1002,10 @@ TEST_F(NullSemanticsPipelineTest, WhereIsErrorAnd) { // This happens if either a or b is missing. pipeline = pipeline.AddingStage( std::make_shared(IsErrorExpr(AndExpr( // Use IsErrorExpr helper - {EqExpr({std::make_shared("a"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("b"), - SharedConstant(Value(true))})})))); + {EqualExpr( + {std::make_shared("a"), SharedConstant(Value(true))}), + EqualExpr({std::make_shared("b"), + SharedConstant(Value(true))})})))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc2, doc5, doc8)); @@ -1015,8 +1020,9 @@ TEST_F(NullSemanticsPipelineTest, WhereOr) { RealtimePipeline pipeline = StartPipeline("k"); // Need explicit boolean comparison pipeline = pipeline.AddingStage(std::make_shared(OrExpr( - {EqExpr({std::make_shared("a"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("b"), SharedConstant(Value(true))})}))); + {EqualExpr({std::make_shared("a"), SharedConstant(Value(true))}), + EqualExpr( + {std::make_shared("b"), SharedConstant(Value(true))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc1)); } @@ -1036,8 +1042,9 @@ TEST_F(NullSemanticsPipelineTest, WhereIsNullOr) { RealtimePipeline pipeline = StartPipeline("k"); // Need explicit boolean comparison pipeline = pipeline.AddingStage(std::make_shared(IsNullExpr(OrExpr( - {EqExpr({std::make_shared("a"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("b"), SharedConstant(Value(true))})})))); + {EqualExpr({std::make_shared("a"), SharedConstant(Value(true))}), + EqualExpr( + {std::make_shared("b"), SharedConstant(Value(true))})})))); // Expect docs where (a==true OR b==true) evaluates to NULL. // This happens if neither is true AND at least one is null/missing. @@ -1084,9 +1091,10 @@ TEST_F(NullSemanticsPipelineTest, WhereIsErrorOr) { // This happens if either a or b is missing. pipeline = pipeline.AddingStage( std::make_shared(IsErrorExpr(OrExpr( // Use IsErrorExpr helper - {EqExpr({std::make_shared("a"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("b"), - SharedConstant(Value(true))})})))); + {EqualExpr( + {std::make_shared("a"), SharedConstant(Value(true))}), + EqualExpr({std::make_shared("b"), + SharedConstant(Value(true))})})))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc2, doc5, doc8)); @@ -1108,8 +1116,9 @@ TEST_F(NullSemanticsPipelineTest, WhereXor) { RealtimePipeline pipeline = StartPipeline("k"); // Need explicit boolean comparison and assume XorExpr exists pipeline = pipeline.AddingStage(std::make_shared(XorExpr( - {EqExpr({std::make_shared("a"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("b"), SharedConstant(Value(true))})}))); + {EqualExpr({std::make_shared("a"), SharedConstant(Value(true))}), + EqualExpr( + {std::make_shared("b"), SharedConstant(Value(true))})}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc4)); } @@ -1129,8 +1138,9 @@ TEST_F(NullSemanticsPipelineTest, WhereIsNullXor) { RealtimePipeline pipeline = StartPipeline("k"); // Need explicit boolean comparison and assume XorExpr exists pipeline = pipeline.AddingStage(std::make_shared(IsNullExpr(XorExpr( - {EqExpr({std::make_shared("a"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("b"), SharedConstant(Value(true))})})))); + {EqualExpr({std::make_shared("a"), SharedConstant(Value(true))}), + EqualExpr( + {std::make_shared("b"), SharedConstant(Value(true))})})))); // Expect docs where (a==true XOR b==true) evaluates to NULL. // This happens if either operand is null/missing. @@ -1177,9 +1187,10 @@ TEST_F(NullSemanticsPipelineTest, WhereIsErrorXor) { // This happens if either a or b is missing. pipeline = pipeline.AddingStage( std::make_shared(IsErrorExpr(XorExpr( // Use IsErrorExpr helper - {EqExpr({std::make_shared("a"), SharedConstant(Value(true))}), - EqExpr({std::make_shared("b"), - SharedConstant(Value(true))})})))); + {EqualExpr( + {std::make_shared("a"), SharedConstant(Value(true))}), + EqualExpr({std::make_shared("b"), + SharedConstant(Value(true))})})))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc2, doc5, doc8)); @@ -1196,7 +1207,7 @@ TEST_F(NullSemanticsPipelineTest, WhereNot) { RealtimePipeline pipeline = StartPipeline("k"); pipeline = pipeline.AddingStage(std::make_shared(NotExpr( - EqExpr({std::make_shared("a"), SharedConstant(Value(true))})))); + EqualExpr({std::make_shared("a"), SharedConstant(Value(true))})))); // Based on TS result, only doc2 matches. This implies NOT only works if the // inner expression evaluates cleanly to a boolean. Let's adjust expectation @@ -1215,8 +1226,9 @@ TEST_F(NullSemanticsPipelineTest, WhereIsNullNot) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartPipeline("k"); - pipeline = pipeline.AddingStage(std::make_shared(IsNullExpr(NotExpr( - EqExpr({std::make_shared("a"), SharedConstant(Value(true))}))))); + pipeline = + pipeline.AddingStage(std::make_shared(IsNullExpr(NotExpr(EqualExpr( + {std::make_shared("a"), SharedConstant(Value(true))}))))); // Based on TS result, only doc3 matches. This implies NOT(null_operand) // results in null. Let's adjust expectation to match TS. @@ -1243,7 +1255,7 @@ TEST_F(NullSemanticsPipelineTest, WhereIsErrorNot) { // This happens if a is missing. pipeline = pipeline.AddingStage( std::make_shared(IsErrorExpr(NotExpr( // Use IsErrorExpr helper - EqExpr( + EqualExpr( {std::make_shared("a"), SharedConstant(Value(true))}))))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc4)); diff --git a/Firestore/core/test/unit/core/pipeline/number_semantics_test.cc b/Firestore/core/test/unit/core/pipeline/number_semantics_test.cc index cf05c027088..2f2aff0ead5 100644 --- a/Firestore/core/test/unit/core/pipeline/number_semantics_test.cc +++ b/Firestore/core/test/unit/core/pipeline/number_semantics_test.cc @@ -66,15 +66,15 @@ using testutil::ArrayContainsAllExpr; using testutil::ArrayContainsAnyExpr; using testutil::ArrayContainsExpr; using testutil::EqAnyExpr; -using testutil::EqExpr; -using testutil::GteExpr; -using testutil::GtExpr; +using testutil::EqualExpr; +using testutil::GreaterThanExpr; +using testutil::GreaterThanOrEqualExpr; using testutil::IsNanExpr; using testutil::IsNullExpr; -using testutil::LteExpr; -using testutil::LtExpr; -using testutil::NeqExpr; +using testutil::LessThanExpr; +using testutil::LessThanOrEqualExpr; using testutil::NotEqAnyExpr; +using testutil::NotEqualExpr; using testutil::NotExpr; using testutil::OrExpr; using testutil::XorExpr; @@ -101,8 +101,8 @@ TEST_F(NumberSemanticsPipelineTest, ZeroNegativeDoubleZero) { RealtimePipeline pipeline = StartPipeline("/users"); // Assuming /users based on keys // Firestore treats 0, -0, 0.0, -0.0 as equal. - pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("score"), SharedConstant(Value(-0.0))}))); + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("score"), SharedConstant(Value(-0.0))}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc1, doc2, doc3, doc4)); @@ -117,8 +117,8 @@ TEST_F(NumberSemanticsPipelineTest, ZeroNegativeIntegerZero) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4, doc5}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("score"), SharedConstant(Value(-0LL))}))); + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("score"), SharedConstant(Value(-0LL))}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc1, doc2, doc3, doc4)); @@ -133,8 +133,8 @@ TEST_F(NumberSemanticsPipelineTest, ZeroPositiveDoubleZero) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4, doc5}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("score"), SharedConstant(Value(0.0))}))); + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("score"), SharedConstant(Value(0.0))}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc1, doc2, doc3, doc4)); @@ -149,8 +149,8 @@ TEST_F(NumberSemanticsPipelineTest, ZeroPositiveIntegerZero) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4, doc5}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("score"), SharedConstant(Value(0LL))}))); + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("score"), SharedConstant(Value(0LL))}))); EXPECT_THAT(RunPipeline(pipeline, documents), UnorderedElementsAre(doc1, doc2, doc3, doc4)); @@ -166,7 +166,7 @@ TEST_F(NumberSemanticsPipelineTest, EqualNan) { RealtimePipeline pipeline = StartPipeline("/users"); // NaN is not equal to anything, including NaN. - pipeline = pipeline.AddingStage(std::make_shared(EqExpr( + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( {std::make_shared("age"), SharedConstant(Value(std::numeric_limits::quiet_NaN()))}))); @@ -183,7 +183,7 @@ TEST_F(NumberSemanticsPipelineTest, LessThanNan) { RealtimePipeline pipeline = StartPipeline("/users"); // Comparisons with NaN are always false. - pipeline = pipeline.AddingStage(std::make_shared(LtExpr( + pipeline = pipeline.AddingStage(std::make_shared(LessThanExpr( {std::make_shared("age"), SharedConstant(Value(std::numeric_limits::quiet_NaN()))}))); @@ -200,7 +200,7 @@ TEST_F(NumberSemanticsPipelineTest, LessThanEqualNan) { RealtimePipeline pipeline = StartPipeline("/users"); // Comparisons with NaN are always false. - pipeline = pipeline.AddingStage(std::make_shared(LteExpr( + pipeline = pipeline.AddingStage(std::make_shared(LessThanOrEqualExpr( {std::make_shared("age"), SharedConstant(Value(std::numeric_limits::quiet_NaN()))}))); @@ -217,9 +217,10 @@ TEST_F(NumberSemanticsPipelineTest, GreaterThanEqualNan) { RealtimePipeline pipeline = StartPipeline("/users"); // Comparisons with NaN are always false. - pipeline = pipeline.AddingStage(std::make_shared(GteExpr( - {std::make_shared("age"), - SharedConstant(Value(std::numeric_limits::quiet_NaN()))}))); + pipeline = + pipeline.AddingStage(std::make_shared(GreaterThanOrEqualExpr( + {std::make_shared("age"), + SharedConstant(Value(std::numeric_limits::quiet_NaN()))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } @@ -234,7 +235,7 @@ TEST_F(NumberSemanticsPipelineTest, GreaterThanNan) { RealtimePipeline pipeline = StartPipeline("/users"); // Comparisons with NaN are always false. - pipeline = pipeline.AddingStage(std::make_shared(GtExpr( + pipeline = pipeline.AddingStage(std::make_shared(GreaterThanExpr( {std::make_shared("age"), SharedConstant(Value(std::numeric_limits::quiet_NaN()))}))); @@ -251,7 +252,7 @@ TEST_F(NumberSemanticsPipelineTest, NotEqualNan) { RealtimePipeline pipeline = StartPipeline("/users"); // != NaN is always true (as NaN != NaN). - pipeline = pipeline.AddingStage(std::make_shared(NeqExpr( + pipeline = pipeline.AddingStage(std::make_shared(NotEqualExpr( {std::make_shared("age"), SharedConstant(Value(std::numeric_limits::quiet_NaN()))}))); @@ -388,10 +389,10 @@ TEST_F(NumberSemanticsPipelineTest, ArrayWithNan) { RealtimePipeline pipeline = StartPipeline("/k"); // Equality filters never match NaN values, even within arrays. - pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("foo"), - SharedConstant(Value( - Array(Value(std::numeric_limits::quiet_NaN()))))}))); + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("foo"), + SharedConstant( + Value(Array(Value(std::numeric_limits::quiet_NaN()))))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre()); } diff --git a/Firestore/core/test/unit/core/pipeline/sort_test.cc b/Firestore/core/test/unit/core/pipeline/sort_test.cc index 3802324eb29..9de47dec73e 100644 --- a/Firestore/core/test/unit/core/pipeline/sort_test.cc +++ b/Firestore/core/test/unit/core/pipeline/sort_test.cc @@ -66,9 +66,9 @@ using testutil::Value; // Expression helpers using testutil::AddExpr; using testutil::AndExpr; -using testutil::EqExpr; +using testutil::EqualExpr; using testutil::ExistsExpr; -using testutil::GtExpr; +using testutil::GreaterThanExpr; using testutil::NotExpr; using testutil::RegexMatchExpr; @@ -147,8 +147,8 @@ TEST_F(SortPipelineTest, SingleResultAscendingImplicitExists) { auto doc1 = Doc("users/a", 1000, Map("name", "alice", "age", 10LL)); PipelineInputOutputVector documents = {doc1}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("age"), SharedConstant(Value(10LL))}))); + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("age"), SharedConstant(Value(10LL))}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("age"), Ordering::Direction::ASCENDING)})); @@ -181,8 +181,8 @@ TEST_F(SortPipelineTest, SingleResultDescendingImplicitExists) { auto doc1 = Doc("users/a", 1000, Map("name", "alice", "age", 10LL)); PipelineInputOutputVector documents = {doc1}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("age"), SharedConstant(Value(10LL))}))); + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("age"), SharedConstant(Value(10LL))}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("age"), Ordering::Direction::DESCENDING)})); @@ -230,8 +230,8 @@ TEST_F(SortPipelineTest, MultipleResultsAmbiguousOrderImplicitExists) { auto doc5 = Doc("users/e", 1000, Map("name", "eric", "age", 10.0)); PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4, doc5}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - GtExpr({std::make_shared("age"), SharedConstant(Value(0.0))}))); + pipeline = pipeline.AddingStage(std::make_shared(GreaterThanExpr( + {std::make_shared("age"), SharedConstant(Value(0.0))}))); pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("age"), Ordering::Direction::DESCENDING)})); @@ -308,8 +308,8 @@ TEST_F(SortPipelineTest, MultipleResultsFullOrderImplicitExists) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4, doc5}; RealtimePipeline pipeline = StartPipeline("/users"); pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("age"), - std::make_shared("age")}))); // Implicit exists age + EqualExpr({std::make_shared("age"), + std::make_shared("age")}))); // Implicit exists age pipeline = pipeline.AddingStage(std::make_shared( RegexMatchExpr(std::make_shared("name"), SharedConstant(Value(".*"))))); // Implicit exists name diff --git a/Firestore/core/test/unit/core/pipeline/unicode_test.cc b/Firestore/core/test/unit/core/pipeline/unicode_test.cc index 4828a2a23cc..41b76568a69 100644 --- a/Firestore/core/test/unit/core/pipeline/unicode_test.cc +++ b/Firestore/core/test/unit/core/pipeline/unicode_test.cc @@ -66,11 +66,11 @@ using testutil::Value; // Expression helpers using testutil::AndExpr; using testutil::Constant; // Renamed from ConstantExpr -using testutil::EqExpr; -using testutil::GteExpr; -using testutil::GtExpr; -using testutil::LteExpr; -using testutil::LtExpr; +using testutil::EqualExpr; +using testutil::GreaterThanExpr; +using testutil::GreaterThanOrEqualExpr; +using testutil::LessThanExpr; +using testutil::LessThanOrEqualExpr; // Test Fixture for Unicode Pipeline tests class UnicodePipelineTest : public ::testing::Test { @@ -111,10 +111,11 @@ TEST_F(UnicodePipelineTest, UnicodeSurrogates) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline = StartDatabasePipeline(); pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {LteExpr({std::make_shared("str"), - SharedConstant("🄟")}), // Renamed from ConstantExpr - GteExpr({std::make_shared("str"), - SharedConstant("P")})}))); // Renamed from ConstantExpr + {LessThanOrEqualExpr({std::make_shared("str"), + SharedConstant("🄟")}), // Renamed from ConstantExpr + GreaterThanOrEqualExpr( + {std::make_shared("str"), + SharedConstant("P")})}))); // Renamed from ConstantExpr pipeline = pipeline.AddingStage( std::make_shared(std::vector{Ordering( std::make_unique("str"), Ordering::Direction::ASCENDING)})); diff --git a/Firestore/core/test/unit/core/pipeline/where_test.cc b/Firestore/core/test/unit/core/pipeline/where_test.cc index f6753d29475..a50cf1ecacd 100644 --- a/Firestore/core/test/unit/core/pipeline/where_test.cc +++ b/Firestore/core/test/unit/core/pipeline/where_test.cc @@ -70,16 +70,16 @@ using testutil::ArrayContainsAnyExpr; using testutil::ArrayContainsExpr; using testutil::DivideExpr; using testutil::EqAnyExpr; -using testutil::EqExpr; +using testutil::EqualExpr; using testutil::ExistsExpr; -using testutil::GteExpr; -using testutil::GtExpr; +using testutil::GreaterThanExpr; +using testutil::GreaterThanOrEqualExpr; using testutil::IsNanExpr; using testutil::IsNullExpr; -using testutil::LteExpr; -using testutil::LtExpr; +using testutil::LessThanExpr; +using testutil::LessThanOrEqualExpr; // using testutil::NeqAnyExpr; // Not used -using testutil::NeqExpr; +using testutil::NotEqualExpr; using testutil::NotExpr; using testutil::OrExpr; using testutil::RegexMatchExpr; // For 'like' @@ -105,8 +105,9 @@ class WherePipelineTest : public ::testing::Test { TEST_F(WherePipelineTest, EmptyDatabaseReturnsNoResults) { PipelineInputOutputVector documents = {}; RealtimePipeline pipeline = StartDatabasePipeline(); - pipeline = pipeline.AddingStage(std::make_shared( - GteExpr({std::make_shared("age"), SharedConstant(Value(10LL))}))); + pipeline = + pipeline.AddingStage(std::make_shared(GreaterThanOrEqualExpr( + {std::make_shared("age"), SharedConstant(Value(10LL))}))); EXPECT_THAT(RunPipeline(pipeline, documents), IsEmpty()); } @@ -120,10 +121,11 @@ TEST_F(WherePipelineTest, DuplicateConditions) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4, doc5}; RealtimePipeline pipeline = StartDatabasePipeline(); - pipeline = pipeline.AddingStage(std::make_shared(AndExpr( - {GteExpr({std::make_shared("age"), SharedConstant(Value(10.0))}), - GteExpr( - {std::make_shared("age"), SharedConstant(Value(20.0))})}))); + pipeline = pipeline.AddingStage(std::make_shared( + AndExpr({GreaterThanOrEqualExpr({std::make_shared("age"), + SharedConstant(Value(10.0))}), + GreaterThanOrEqualExpr({std::make_shared("age"), + SharedConstant(Value(20.0))})}))); // Note: TS test expected [doc1, doc2, doc3]. Let's re-evaluate based on C++ // types. age >= 10.0 AND age >= 20.0 => age >= 20.0 Matches: doc1 (75.5), @@ -138,12 +140,12 @@ TEST_F(WherePipelineTest, LogicalEquivalentConditionEqual) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline1 = StartDatabasePipeline(); - pipeline1 = pipeline1.AddingStage(std::make_shared( - EqExpr({std::make_shared("age"), SharedConstant(Value(25.0))}))); + pipeline1 = pipeline1.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("age"), SharedConstant(Value(25.0))}))); RealtimePipeline pipeline2 = StartDatabasePipeline(); - pipeline2 = pipeline2.AddingStage(std::make_shared( - EqExpr({SharedConstant(Value(25.0)), std::make_shared("age")}))); + pipeline2 = pipeline2.AddingStage(std::make_shared(EqualExpr( + {SharedConstant(Value(25.0)), std::make_shared("age")}))); auto result1 = RunPipeline(pipeline1, documents); auto result2 = RunPipeline(pipeline2, documents); @@ -159,16 +161,18 @@ TEST_F(WherePipelineTest, LogicalEquivalentConditionAnd) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline1 = StartDatabasePipeline(); - pipeline1 = pipeline1.AddingStage(std::make_shared(AndExpr( - {GtExpr({std::make_shared("age"), SharedConstant(Value(10.0))}), - LtExpr( - {std::make_shared("age"), SharedConstant(Value(70.0))})}))); + pipeline1 = pipeline1.AddingStage(std::make_shared( + AndExpr({GreaterThanExpr({std::make_shared("age"), + SharedConstant(Value(10.0))}), + LessThanExpr({std::make_shared("age"), + SharedConstant(Value(70.0))})}))); RealtimePipeline pipeline2 = StartDatabasePipeline(); - pipeline2 = pipeline2.AddingStage(std::make_shared(AndExpr( - {LtExpr({std::make_shared("age"), SharedConstant(Value(70.0))}), - GtExpr( - {std::make_shared("age"), SharedConstant(Value(10.0))})}))); + pipeline2 = pipeline2.AddingStage(std::make_shared( + AndExpr({LessThanExpr({std::make_shared("age"), + SharedConstant(Value(70.0))}), + GreaterThanExpr({std::make_shared("age"), + SharedConstant(Value(10.0))})}))); auto result1 = RunPipeline(pipeline1, documents); auto result2 = RunPipeline(pipeline2, documents); @@ -185,16 +189,18 @@ TEST_F(WherePipelineTest, LogicalEquivalentConditionOr) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; RealtimePipeline pipeline1 = StartDatabasePipeline(); - pipeline1 = pipeline1.AddingStage(std::make_shared(OrExpr( - {LtExpr({std::make_shared("age"), SharedConstant(Value(10.0))}), - GtExpr( - {std::make_shared("age"), SharedConstant(Value(80.0))})}))); + pipeline1 = pipeline1.AddingStage(std::make_shared( + OrExpr({LessThanExpr({std::make_shared("age"), + SharedConstant(Value(10.0))}), + GreaterThanExpr({std::make_shared("age"), + SharedConstant(Value(80.0))})}))); RealtimePipeline pipeline2 = StartDatabasePipeline(); - pipeline2 = pipeline2.AddingStage(std::make_shared(OrExpr( - {GtExpr({std::make_shared("age"), SharedConstant(Value(80.0))}), - LtExpr( - {std::make_shared("age"), SharedConstant(Value(10.0))})}))); + pipeline2 = pipeline2.AddingStage(std::make_shared( + OrExpr({GreaterThanExpr({std::make_shared("age"), + SharedConstant(Value(80.0))}), + LessThanExpr({std::make_shared("age"), + SharedConstant(Value(10.0))})}))); auto result1 = RunPipeline(pipeline1, documents); auto result2 = RunPipeline(pipeline2, documents); @@ -239,10 +245,12 @@ TEST_F(WherePipelineTest, RepeatedStages) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4, doc5}; RealtimePipeline pipeline = StartDatabasePipeline(); - pipeline = pipeline.AddingStage(std::make_shared( - GteExpr({std::make_shared("age"), SharedConstant(Value(10.0))}))); - pipeline = pipeline.AddingStage(std::make_shared( - GteExpr({std::make_shared("age"), SharedConstant(Value(20.0))}))); + pipeline = + pipeline.AddingStage(std::make_shared(GreaterThanOrEqualExpr( + {std::make_shared("age"), SharedConstant(Value(10.0))}))); + pipeline = + pipeline.AddingStage(std::make_shared(GreaterThanOrEqualExpr( + {std::make_shared("age"), SharedConstant(Value(20.0))}))); // age >= 10.0 THEN age >= 20.0 => age >= 20.0 // Matches: doc1 (75.5), doc2 (25.0), doc3 (100.0) @@ -260,9 +268,9 @@ TEST_F(WherePipelineTest, CompositeEqualities) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4, doc5}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("age"), SharedConstant(Value(75LL))}))); - pipeline = pipeline.AddingStage(std::make_shared(EqExpr( + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("age"), SharedConstant(Value(75LL))}))); + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( {std::make_shared("height"), SharedConstant(Value(55LL))}))); EXPECT_THAT(RunPipeline(pipeline, documents), ElementsAre(doc3)); @@ -277,9 +285,9 @@ TEST_F(WherePipelineTest, CompositeInequalities) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4, doc5}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - GtExpr({std::make_shared("age"), SharedConstant(Value(50LL))}))); - pipeline = pipeline.AddingStage(std::make_shared(LtExpr( + pipeline = pipeline.AddingStage(std::make_shared(GreaterThanExpr( + {std::make_shared("age"), SharedConstant(Value(50LL))}))); + pipeline = pipeline.AddingStage(std::make_shared(LessThanExpr( {std::make_shared("height"), SharedConstant(Value(75LL))}))); // age > 50 AND height < 75 @@ -337,9 +345,9 @@ TEST_F(WherePipelineTest, CompositeMixed) { PipelineInputOutputVector documents = {doc1, doc2, doc3, doc4, doc5}; RealtimePipeline pipeline = StartPipeline("/users"); - pipeline = pipeline.AddingStage(std::make_shared( - EqExpr({std::make_shared("age"), SharedConstant(Value(75LL))}))); - pipeline = pipeline.AddingStage(std::make_shared(GtExpr( + pipeline = pipeline.AddingStage(std::make_shared(EqualExpr( + {std::make_shared("age"), SharedConstant(Value(75LL))}))); + pipeline = pipeline.AddingStage(std::make_shared(GreaterThanExpr( {std::make_shared("height"), SharedConstant(Value(45LL))}))); pipeline = pipeline.AddingStage(std::make_shared( RegexMatchExpr(std::make_shared("last"), @@ -610,9 +618,9 @@ TEST_F(WherePipelineTest, AndExpressionLogicallyEquivalentToSeparatedStages) { PipelineInputOutputVector documents = {doc1, doc2, doc3}; auto equalityArgument1 = - EqExpr({std::make_shared("a"), SharedConstant(Value(1LL))}); + EqualExpr({std::make_shared("a"), SharedConstant(Value(1LL))}); auto equalityArgument2 = - EqExpr({std::make_shared("b"), SharedConstant(Value(2LL))}); + EqualExpr({std::make_shared("b"), SharedConstant(Value(2LL))}); // Combined AND RealtimePipeline pipeline_and_1 = StartDatabasePipeline(); diff --git a/Firestore/core/test/unit/core/pipeline_util_test.cc b/Firestore/core/test/unit/core/pipeline_util_test.cc index c944a842337..b6a9aa1abee 100644 --- a/Firestore/core/test/unit/core/pipeline_util_test.cc +++ b/Firestore/core/test/unit/core/pipeline_util_test.cc @@ -63,18 +63,18 @@ api::RealtimePipeline StartPipeline( api::RealtimePipeline TestPipeline(int id) { auto pipeline = StartPipeline("coll"); if (id == 1) { - pipeline = pipeline.AddingStage( - std::make_shared(testutil::NotExpr(testutil::GtExpr( + pipeline = pipeline.AddingStage(std::make_shared( + testutil::NotExpr(testutil::GreaterThanExpr( {std::make_shared("score"), testutil::SharedConstant(testutil::Value(90LL))})))); } else if (id == 2) { pipeline = pipeline.AddingStage( - std::make_shared(testutil::NotExpr(testutil::LtExpr( + std::make_shared(testutil::NotExpr(testutil::LessThanExpr( {std::make_shared("score"), testutil::SharedConstant(testutil::Value(90LL))})))); } else if (id == 3) { // Same as id 1 - pipeline = pipeline.AddingStage( - std::make_shared(testutil::NotExpr(testutil::GtExpr( + pipeline = pipeline.AddingStage(std::make_shared( + testutil::NotExpr(testutil::GreaterThanExpr( {std::make_shared("score"), testutil::SharedConstant(testutil::Value(90LL))})))); } diff --git a/Firestore/core/test/unit/local/local_serializer_test.cc b/Firestore/core/test/unit/local/local_serializer_test.cc index 577830efe42..83668fdb4e6 100644 --- a/Firestore/core/test/unit/local/local_serializer_test.cc +++ b/Firestore/core/test/unit/local/local_serializer_test.cc @@ -734,8 +734,8 @@ TEST_F(LocalSerializerTest, EncodesTargetDataWithPipeline) { // Construct the pipeline auto ppl = StartPipeline("rooms"); ppl = ppl.AddingStage(std::make_shared( - testutil::EqExpr({std::make_shared("name"), - testutil::SharedConstant("testroom")}))); + testutil::EqualExpr({std::make_shared("name"), + testutil::SharedConstant("testroom")}))); api::Ordering ordering(std::make_unique("age"), api::Ordering::DESCENDING); ppl = ppl.AddingStage( @@ -772,14 +772,14 @@ TEST_F(LocalSerializerTest, EncodesTargetDataWithPipeline) { stage1_arg1->set_reference_value("/rooms"); } - // Stage 2: Where(EqExpr(Field("name"), Value("testroom"))) + // Stage 2: Where(EqualExpr(Field("name"), Value("testroom"))) { google::firestore::v1::Pipeline_Stage* stage2_proto = pipeline_proto_obj->add_stages(); // Changed type stage2_proto->set_name("where"); - v1::Value* stage2_arg1_expr = stage2_proto->add_args(); // The EqExpr + v1::Value* stage2_arg1_expr = stage2_proto->add_args(); // The EqualExpr v1::Function* eq_func = stage2_arg1_expr->mutable_function_value(); - eq_func->set_name("eq"); + eq_func->set_name("equal"); v1::Value* eq_arg1_field = eq_func->add_args(); // Field("name") eq_arg1_field->set_field_reference_value("name"); diff --git a/Firestore/core/test/unit/local/query_engine_test.cc b/Firestore/core/test/unit/local/query_engine_test.cc index 168a4f9f0aa..ff7b53bf9a1 100644 --- a/Firestore/core/test/unit/local/query_engine_test.cc +++ b/Firestore/core/test/unit/local/query_engine_test.cc @@ -1082,10 +1082,11 @@ TEST_P(QueryEngineTest, HandlesServerTimestampEstimate) { auto pipeline = api::RealtimePipeline( {std::make_shared("coll")}, TestSerializer()); - pipeline = pipeline.AddingStage(std::make_shared( - testutil::GtExpr({testutil::TimestampToUnixMillisExpr( - {std::make_shared("timestamp")}), - testutil::SharedConstant(testutil::Value(1000))}))); + pipeline = pipeline.AddingStage( + std::make_shared(testutil::GreaterThanExpr( + {testutil::TimestampToUnixMillisExpr( + {std::make_shared("timestamp")}), + testutil::SharedConstant(testutil::Value(1000))}))); DocumentSet result1 = ExpectFullCollectionScan( [&] { return RunPipeline(pipeline, kMissingLastLimboFreeSnapshot); }); @@ -1118,9 +1119,10 @@ TEST_P(QueryEngineTest, HandlesServerTimestampPrevious) { auto pipeline = api::RealtimePipeline( {std::make_shared("coll")}, TestSerializer()); - pipeline = pipeline.AddingStage(std::make_shared( - testutil::EqExpr({std::make_shared("matches"), - testutil::SharedConstant(testutil::Value(true))}))); + pipeline = + pipeline.AddingStage(std::make_shared(testutil::EqualExpr( + {std::make_shared("matches"), + testutil::SharedConstant(testutil::Value(true))}))); DocumentSet result1 = ExpectFullCollectionScan( [&] { return RunPipeline(pipeline, kMissingLastLimboFreeSnapshot); }); diff --git a/Firestore/core/test/unit/testutil/expression_test_util.h b/Firestore/core/test/unit/testutil/expression_test_util.h index 3386c03d2fb..616fbd64df8 100644 --- a/Firestore/core/test/unit/testutil/expression_test_util.h +++ b/Firestore/core/test/unit/testutil/expression_test_util.h @@ -211,46 +211,49 @@ inline std::shared_ptr TimestampAddExpr(std::shared_ptr timestamp, // --- Comparison Expression Helpers --- -inline std::shared_ptr EqExpr( +inline std::shared_ptr EqualExpr( std::initializer_list> params) { - HARD_ASSERT(params.size() == 2, "EqExpr requires exactly 2 parameters"); + HARD_ASSERT(params.size() == 2, "EqualExpr requires exactly 2 parameters"); return std::make_shared( - "eq", std::vector>(params)); + "equal", std::vector>(params)); } -inline std::shared_ptr NeqExpr( +inline std::shared_ptr NotEqualExpr( std::initializer_list> params) { - HARD_ASSERT(params.size() == 2, "NeqExpr requires exactly 2 parameters"); + HARD_ASSERT(params.size() == 2, "NotEqualExpr requires exactly 2 parameters"); return std::make_shared( - "neq", std::vector>(params)); + "not_equal", std::vector>(params)); } -inline std::shared_ptr LtExpr( +inline std::shared_ptr LessThanExpr( std::initializer_list> params) { - HARD_ASSERT(params.size() == 2, "LtExpr requires exactly 2 parameters"); + HARD_ASSERT(params.size() == 2, "LessThanExpr requires exactly 2 parameters"); return std::make_shared( - "lt", std::vector>(params)); + "less_than", std::vector>(params)); } -inline std::shared_ptr LteExpr( +inline std::shared_ptr LessThanOrEqualExpr( std::initializer_list> params) { - HARD_ASSERT(params.size() == 2, "LteExpr requires exactly 2 parameters"); + HARD_ASSERT(params.size() == 2, + "LessThanOrEqualExpr requires exactly 2 parameters"); return std::make_shared( - "lte", std::vector>(params)); + "less_than_or_equal", std::vector>(params)); } -inline std::shared_ptr GtExpr( +inline std::shared_ptr GreaterThanExpr( std::initializer_list> params) { - HARD_ASSERT(params.size() == 2, "GtExpr requires exactly 2 parameters"); + HARD_ASSERT(params.size() == 2, + "GreaterThanExpr requires exactly 2 parameters"); return std::make_shared( - "gt", std::vector>(params)); + "greater_than", std::vector>(params)); } -inline std::shared_ptr GteExpr( +inline std::shared_ptr GreaterThanOrEqualExpr( std::initializer_list> params) { - HARD_ASSERT(params.size() == 2, "GteExpr requires exactly 2 parameters"); + HARD_ASSERT(params.size() == 2, + "GreaterThanOrEqualExpr requires exactly 2 parameters"); return std::make_shared( - "gte", std::vector>(params)); + "greater_than_or_equal", std::vector>(params)); } // --- Array Expression Helpers --- @@ -314,7 +317,7 @@ inline std::shared_ptr EqAnyExpr(std::shared_ptr search, std::vector> operands; operands.push_back(std::move(search)); operands.push_back(std::move(values)); - return std::make_shared("eq_any", std::move(operands)); + return std::make_shared("equal_any", std::move(operands)); } inline std::shared_ptr NotEqAnyExpr(std::shared_ptr search, @@ -322,7 +325,7 @@ inline std::shared_ptr NotEqAnyExpr(std::shared_ptr search, std::vector> operands; operands.push_back(std::move(search)); operands.push_back(std::move(values)); - return std::make_shared("not_eq_any", std::move(operands)); + return std::make_shared("not_equal_any", std::move(operands)); } inline std::shared_ptr IsNanExpr(std::shared_ptr operand) { @@ -350,14 +353,14 @@ inline std::shared_ptr IsErrorExpr(std::shared_ptr operand) { "is_error", std::vector>{std::move(operand)}); } -inline std::shared_ptr LogicalMaxExpr( +inline std::shared_ptr MaximumExpr( std::vector> operands) { - return std::make_shared("logical_maximum", std::move(operands)); + return std::make_shared("maximum", std::move(operands)); } -inline std::shared_ptr LogicalMinExpr( +inline std::shared_ptr MinimumExpr( std::vector> operands) { - return std::make_shared("logical_minimum", std::move(operands)); + return std::make_shared("minimum", std::move(operands)); } // --- Debugging Expression Helpers --- @@ -669,9 +672,9 @@ inline std::shared_ptr ToUpperExpr(std::shared_ptr operand) { "to_upper", std::vector>{std::move(operand)}); } -inline std::shared_ptr ReverseExpr(std::shared_ptr operand) { +inline std::shared_ptr StringReverseExpr(std::shared_ptr operand) { return std::make_shared( - "reverse", std::vector>{std::move(operand)}); + "string_reverse", std::vector>{std::move(operand)}); } inline std::shared_ptr TrimExpr(std::shared_ptr operand) { @@ -700,10 +703,10 @@ inline std::shared_ptr RegexMatchExpr(std::shared_ptr value, std::vector>{std::move(value), std::move(regex)}); } -inline std::shared_ptr StrContainsExpr(std::shared_ptr value, - std::shared_ptr search) { +inline std::shared_ptr StringContainsExpr(std::shared_ptr value, + std::shared_ptr search) { return std::make_shared( - "str_contains", + "string_contains", std::vector>{std::move(value), std::move(search)}); } @@ -721,9 +724,9 @@ inline std::shared_ptr EndsWithExpr(std::shared_ptr value, std::vector>{std::move(value), std::move(suffix)}); } -inline std::shared_ptr StrConcatExpr( +inline std::shared_ptr StringConcatExpr( std::vector> operands) { - return std::make_shared("str_concat", std::move(operands)); + return std::make_shared("string_concat", std::move(operands)); } // --- Vector Expression Helpers ---