diff --git a/crates/cli/src/introspection/type_unification.rs b/crates/cli/src/introspection/type_unification.rs index 31e539e1..bf997c3f 100644 --- a/crates/cli/src/introspection/type_unification.rs +++ b/crates/cli/src/introspection/type_unification.rs @@ -174,6 +174,16 @@ pub fn unify_object_types( merged_type_map.into_values().collect() } +/// True iff we consider a to be a supertype of b. +/// +/// Note that if you add more supertypes here then it is important to also update the custom +/// equality check in our tests in mongodb_agent_common::query::serialization::tests. Equality +/// needs to be transitive over supertypes, so for example if we have, +/// +/// (Double, Int), (Decimal, Double) +/// +/// then in addition to comparing ints to doubles, and doubles to decimals, we also need to compare +/// decimals to ints. fn is_supertype(a: &BsonScalarType, b: &BsonScalarType) -> bool { matches!((a, b), (Double, Int)) } diff --git a/crates/mongodb-agent-common/proptest-regressions/query/serialization/tests.txt b/crates/mongodb-agent-common/proptest-regressions/query/serialization/tests.txt index 8a816d59..8304681d 100644 --- a/crates/mongodb-agent-common/proptest-regressions/query/serialization/tests.txt +++ b/crates/mongodb-agent-common/proptest-regressions/query/serialization/tests.txt @@ -8,3 +8,4 @@ cc 2efdea7f185f2f38ae643782b3523014ab7b8236e36a79cc6b7a7cac74b06f79 # shrinks to cc 26e2543468ab6d4ffa34f9f8a2c920801ef38a35337557a8f4e74c92cf57e344 # shrinks to bson = Document({" ": Document({"ยก": DateTime(1970-01-01 0:00:00.001 +00:00:00)})}) cc 7d760e540b56fedac7dd58e5bdb5bb9613b9b0bc6a88acfab3fc9c2de8bf026d # shrinks to bson = Document({"A": Array([Null, Undefined])}) cc 21360610045c5a616b371fb8d5492eb0c22065d62e54d9c8a8761872e2e192f3 # shrinks to bson = Array([Document({}), Document({" ": Null})]) +cc 8842e7f78af24e19847be5d8ee3d47c547ef6c1bb54801d360a131f41a87f4fa diff --git a/crates/mongodb-agent-common/src/query/serialization/tests.rs b/crates/mongodb-agent-common/src/query/serialization/tests.rs index 75395f41..9d65368b 100644 --- a/crates/mongodb-agent-common/src/query/serialization/tests.rs +++ b/crates/mongodb-agent-common/src/query/serialization/tests.rs @@ -21,8 +21,10 @@ proptest! { let json = bson_to_json(&inferred_type, bson.clone()).map_err(|e| error_context("error converting bson to json", e.to_string()))?; let actual = json_to_bson(&inferred_type, json.clone()).map_err(|e| error_context("error converting json to bson", e.to_string()))?; - prop_assert_eq!(actual, bson, - "\ninferred type: {:?}\nobject types: {:?}\njson_representation: {}", + prop_assert!(custom_eq(&actual, &bson), + "`(left == right)`\nleft: `{:?}`\nright: `{:?}`\ninferred type: {:?}\nobject types: {:?}\njson_representation: {}", + actual, + bson, inferred_type, object_types, serde_json::to_string_pretty(&json).unwrap() @@ -40,3 +42,22 @@ proptest! { prop_assert_eq!(actual, bson, "json representation: {}", json) } } + +/// We are treating doubles as a superset of ints, so we need an equality check that allows +/// comparing those types. +fn custom_eq(a: &Bson, b: &Bson) -> bool { + match (a, b) { + (Bson::Double(a), Bson::Int32(b)) | (Bson::Int32(b), Bson::Double(a)) => *a == *b as f64, + (Bson::Array(xs), Bson::Array(ys)) => { + xs.len() == ys.len() && xs.iter().zip(ys.iter()).all(|(x, y)| custom_eq(x, y)) + } + (Bson::Document(a), Bson::Document(b)) => { + a.len() == b.len() + && a.iter().all(|(key_a, value_a)| match b.get(key_a) { + Some(value_b) => custom_eq(value_a, value_b), + None => false, + }) + } + _ => a == b, + } +}