icydb-core 0.180.11

IcyDB — A schema-first typed query engine and persistence runtime for Internet Computer canisters
Documentation
use crate::{
    db::predicate::{
        CoercionId, CompareOp, ComparePredicate, Predicate, encoding::encode_predicate_sort_key,
    },
    value::Value,
};

#[test]
fn predicate_sort_key_normalizes_map_entry_order() {
    let map_a = Value::Map(vec![
        (Value::Text("z".to_string()), Value::Int64(9)),
        (Value::Text("a".to_string()), Value::Int64(1)),
    ]);
    let map_b = Value::Map(vec![
        (Value::Text("a".to_string()), Value::Int64(1)),
        (Value::Text("z".to_string()), Value::Int64(9)),
    ]);
    let predicate_a = Predicate::Compare(ComparePredicate::eq("payload".to_string(), map_a));
    let predicate_b = Predicate::Compare(ComparePredicate::eq("payload".to_string(), map_b));

    assert_eq!(
        encode_predicate_sort_key(&predicate_a),
        encode_predicate_sort_key(&predicate_b)
    );
}

#[test]
fn predicate_sort_key_normalizes_duplicate_map_keys_by_value_order() {
    let map_a = Value::Map(vec![
        (Value::Text("a".to_string()), Value::Int64(2)),
        (Value::Text("a".to_string()), Value::Int64(1)),
    ]);
    let map_b = Value::Map(vec![
        (Value::Text("a".to_string()), Value::Int64(1)),
        (Value::Text("a".to_string()), Value::Int64(2)),
    ]);
    let predicate_a = Predicate::Compare(ComparePredicate::eq("payload".to_string(), map_a));
    let predicate_b = Predicate::Compare(ComparePredicate::eq("payload".to_string(), map_b));

    assert_eq!(
        encode_predicate_sort_key(&predicate_a),
        encode_predicate_sort_key(&predicate_b)
    );
}

#[test]
fn predicate_sort_key_normalizes_in_list_literal_order() {
    let predicate_a = Predicate::Compare(ComparePredicate::in_(
        "rank".to_string(),
        vec![Value::Nat64(3), Value::Nat64(1), Value::Nat64(2)],
    ));
    let predicate_b = Predicate::Compare(ComparePredicate::in_(
        "rank".to_string(),
        vec![Value::Nat64(1), Value::Nat64(2), Value::Nat64(3)],
    ));

    assert_eq!(
        encode_predicate_sort_key(&predicate_a),
        encode_predicate_sort_key(&predicate_b)
    );
}

#[test]
fn predicate_sort_key_normalizes_in_list_duplicate_literals() {
    let predicate_a = Predicate::Compare(ComparePredicate::in_(
        "rank".to_string(),
        vec![
            Value::Nat64(3),
            Value::Nat64(1),
            Value::Nat64(3),
            Value::Nat64(2),
        ],
    ));
    let predicate_b = Predicate::Compare(ComparePredicate::in_(
        "rank".to_string(),
        vec![Value::Nat64(1), Value::Nat64(2), Value::Nat64(3)],
    ));

    assert_eq!(
        encode_predicate_sort_key(&predicate_a),
        encode_predicate_sort_key(&predicate_b)
    );
}

#[test]
fn predicate_sort_key_numeric_widen_treats_equivalent_literal_subtypes_as_identical() {
    let predicate_int = Predicate::Compare(ComparePredicate::with_coercion(
        "rank",
        CompareOp::Eq,
        Value::Int64(1),
        CoercionId::NumericWiden,
    ));
    let predicate_decimal = Predicate::Compare(ComparePredicate::with_coercion(
        "rank",
        CompareOp::Eq,
        Value::Decimal(crate::types::Decimal::new(10, 1)),
        CoercionId::NumericWiden,
    ));

    assert_eq!(
        encode_predicate_sort_key(&predicate_int),
        encode_predicate_sort_key(&predicate_decimal)
    );
}

#[test]
fn predicate_sort_key_strict_keeps_numeric_literal_subtypes_distinct() {
    let predicate_int = Predicate::Compare(ComparePredicate::with_coercion(
        "rank",
        CompareOp::Eq,
        Value::Int64(1),
        CoercionId::Strict,
    ));
    let predicate_decimal = Predicate::Compare(ComparePredicate::with_coercion(
        "rank",
        CompareOp::Eq,
        Value::Decimal(crate::types::Decimal::new(10, 1)),
        CoercionId::Strict,
    ));

    assert_ne!(
        encode_predicate_sort_key(&predicate_int),
        encode_predicate_sort_key(&predicate_decimal)
    );
}

#[test]
fn predicate_sort_key_text_casefold_treats_case_only_literals_as_identical() {
    let predicate_lower = Predicate::Compare(ComparePredicate::with_coercion(
        "name",
        CompareOp::Eq,
        Value::Text("ada".to_string()),
        CoercionId::TextCasefold,
    ));
    let predicate_upper = Predicate::Compare(ComparePredicate::with_coercion(
        "name",
        CompareOp::Eq,
        Value::Text("ADA".to_string()),
        CoercionId::TextCasefold,
    ));

    assert_eq!(
        encode_predicate_sort_key(&predicate_lower),
        encode_predicate_sort_key(&predicate_upper)
    );
}

#[test]
fn predicate_sort_key_strict_keeps_text_case_variants_distinct() {
    let predicate_lower = Predicate::Compare(ComparePredicate::with_coercion(
        "name",
        CompareOp::Eq,
        Value::Text("ada".to_string()),
        CoercionId::Strict,
    ));
    let predicate_upper = Predicate::Compare(ComparePredicate::with_coercion(
        "name",
        CompareOp::Eq,
        Value::Text("ADA".to_string()),
        CoercionId::Strict,
    ));

    assert_ne!(
        encode_predicate_sort_key(&predicate_lower),
        encode_predicate_sort_key(&predicate_upper)
    );
}

#[test]
fn predicate_sort_key_text_casefold_normalizes_in_list_case_variants() {
    let predicate_mixed = Predicate::Compare(ComparePredicate::with_coercion(
        "name",
        CompareOp::In,
        Value::List(vec![
            Value::Text("ADA".to_string()),
            Value::Text("ada".to_string()),
            Value::Text("Bob".to_string()),
        ]),
        CoercionId::TextCasefold,
    ));
    let predicate_canonical = Predicate::Compare(ComparePredicate::with_coercion(
        "name",
        CompareOp::In,
        Value::List(vec![
            Value::Text("ada".to_string()),
            Value::Text("bob".to_string()),
        ]),
        CoercionId::TextCasefold,
    ));

    assert_eq!(
        encode_predicate_sort_key(&predicate_mixed),
        encode_predicate_sort_key(&predicate_canonical)
    );
}