///|
fn num_of(v : Value) -> Num? {
match v {
Int(n) => Some(num_of_int64(n))
BigInt(n) => Some(num_of_bigint(n))
Float(d) => Some(num_of_double(d))
Decimal(d) => Some(num_of_decimal(d))
_ => None
}
}
///|
fn lowered(v : Value) -> Value? {
try v.lower() catch {
_ => None
} noraise {
x => Some(x)
}
}
///|
/// The spec's `=` for two non-absent, lowered values (spec 4.2 rule 3).
fn deep_equal(a : Value, b : Value) -> Bool {
match (num_of(a), num_of(b)) {
(Some(x), Some(y)) =>
return !(x is NaN) && !(y is NaN) && compare_num(x, y) == 0
(Some(_), None) | (None, Some(_)) => return false
_ => ()
}
match (a, b) {
(Bool(x), Bool(y)) => x == y
(String(x), String(y)) => x == y
(Clob(x) | Blob(x), Clob(y) | Blob(y)) => x == y
(Date(x), Date(y)) => x == y
(Time(x), Time(y)) =>
match (x.offset, y.offset) {
(Some(_), Some(_)) => x.utc_key() == y.utc_key()
(None, None) => x.local_key() == y.local_key()
_ => false
}
(Timestamp(x), Timestamp(y)) =>
match (x.time.offset, y.time.offset) {
(Some(_), Some(_)) => x.utc_key() == y.utc_key()
(None, None) => x.local_key() == y.local_key()
_ => false
}
(IntervalYM(x), IntervalYM(y)) => x == y
(IntervalDT(x), IntervalDT(y)) => x == y
(List(xs), List(ys)) =>
xs.length() == ys.length() &&
xs.iter().zip(ys.iter()).all(pair => eqg(pair.0, pair.1))
(Bag(x), Bag(y)) => match_multiset(x.items(), y.items(), eqg)
(Tuple(x), Tuple(y)) =>
match_multiset(x.fields(), y.fields(), (p, q) => {
p.0 == q.0 && eqg(p.1, q.1)
})
// Type parameters are ignored (RFC 0104 equality; Kotlin's comparator).
// Id-based; payloads compared with eqg (spec M1b section 4.2).
(Graph(x), Graph(y)) => same_graph(x, y, eqg)
(Map(x), Map(y)) =>
match_multiset(x.entries(), y.entries(), (p, q) => {
eqg(p.0, q.0) && eqg(p.1, q.1)
})
_ => false
}
}
///|
/// The PartiQL `=` operator: MISSING if either side is MISSING, else NULL if
/// either side is NULL, else a Bool. Never fails on mixed types.
pub fn sql_equals(a : Value, b : Value) -> Value {
match (lowered(a), lowered(b)) {
(Some(x), Some(y)) =>
match (x, y) {
(Missing, _) | (_, Missing) => Missing
(Null, _) | (_, Null) => Null
_ => Bool(deep_equal(x, y))
}
_ => Bool(a == b)
}
}
///|
/// Grouping equivalence: NULL eqg NULL, MISSING eqg MISSING, NaN eqg NaN;
/// otherwise the same as `=`.
pub fn eqg(a : Value, b : Value) -> Bool {
match (lowered(a), lowered(b)) {
(Some(x), Some(y)) =>
match (x, y) {
(Null, Null) | (Missing, Missing) => true
(Null | Missing, _) | (_, Null | Missing) => false
(Float(p), Float(q)) if p.is_nan() && q.is_nan() => true
_ => deep_equal(x, y)
}
_ => a == b
}
}