uqa-execution 0.4.5

Volcano physical operators with row-batch pipelines
//
// Unified Query Algebra
//
// Copyright (c) 2023-2026 Cognica, Inc.
//

use super::*;
use std::sync::Arc;

fn fixture() -> (TableSchema, TableConstraintSet, KeyConstraintNames) {
    let key: TableKeyConstraint = serde_json::from_value(serde_json::json!({
        "name": "original", "columns": ["v"], "kind": "Unique",
        "catalog_identity": {"object_id": vec![3; 16], "oid": 16384}
    }))
    .unwrap();
    let constraints = TableConstraintSet {
        key_constraints: vec![key],
        ..Default::default()
    };
    let schema = TableSchema {
        relation: RelationIdentity::new("public", "t"),
        security: uqa_storage::RelationSecurityRow::legacy("uqa"),
        object_id: [1; 16],
        storage_generation: [2; 16],
        analyzer_json: "{}".into(),
        fts_fields: Vec::new(),
        vector_fields: Vec::new(),
        columns_json: "[]".into(),
        constraints_json: encode(&constraints).unwrap(),
    };
    let names = KeyConstraintNames {
        names: Some(BTreeMap::from([(
            [3; 16],
            KeyName {
                table: schema.relation.clone(),
                table_object_id: schema.object_id,
                name: "current".into(),
            },
        )])),
    };
    (schema, constraints, names)
}

#[test]
fn structural_storage_rehydrates_the_current_owned_name_without_changing_identity() {
    let (schema, mut expected, names) = fixture();
    let stored: TableConstraintSet = serde_json::from_str(&schema.constraints_json).unwrap();
    assert!(stored.key_constraints[0].name.is_none());
    expected.key_constraints[0].name = Some("current".into());
    assert_eq!(
        serde_json::to_value(names.decode(&schema).unwrap()).unwrap(),
        serde_json::to_value(expected).unwrap(),
    );
}

#[test]
fn missing_recreated_or_redundant_name_owners_are_rejected() {
    let (schema, constraints, mut names) = fixture();
    let mut recreated = schema.clone();
    recreated.object_id = [4; 16];
    assert!(names.decode(&recreated).is_err());
    let mut duplicated = schema.clone();
    duplicated.constraints_json = serde_json::to_string(&constraints).unwrap();
    assert!(names.decode(&duplicated).is_err());
    names.names.as_mut().unwrap().clear();
    assert!(names.decode(&schema).is_err());
}

#[test]
fn a_legacy_declaration_keeps_its_name_until_registry_conversion() {
    let (mut schema, constraints, _) = fixture();
    let names = KeyConstraintNames { names: None };
    schema.constraints_json = names.encode(&constraints).unwrap();
    assert_eq!(
        serde_json::to_value(names.decode(&schema).unwrap()).unwrap(),
        serde_json::to_value(constraints).unwrap(),
    );
}

#[test]
fn candidate_names_follow_catalog_identity_without_replacing_key_structure() {
    let (_, mut candidate, _) = fixture();
    let mut current_key = candidate.key_constraints[0].clone();
    current_key.name = Some("renamed".into());
    candidate.hierarchy.partition_inherited_key_constraints = candidate.key_constraints.clone();
    let mut added = candidate.key_constraints[0].clone();
    added.catalog_identity.as_mut().unwrap().object_id = [4; 16];
    added.name = Some("new_key".into());
    candidate.key_constraints.push(added.clone());
    candidate.key_constraints[0].columns = vec!["new_column".into()];
    let current = crate::catalog::CatalogTableSnapshot {
        object_id: [1; 16],
        security: std::sync::Arc::new(crate::catalog::security::BoundTableSecurity::owner(
            uqa_sql::catalog::roles::RoleIdentity::BOOTSTRAP,
        )),
        columns: Arc::default(),
        columns_declared: true,
        checks: Arc::default(),
        foreign_keys: Arc::default(),
        keys: vec![current_key].into(),
        hierarchy: Arc::default(),
        persistence: uqa_sql::ast::RelationPersistence::Permanent,
    };
    rebind_current_key_names(
        candidate.key_constraints.iter_mut().chain(
            candidate
                .hierarchy
                .partition_inherited_key_constraints
                .iter_mut(),
        ),
        &current,
    );
    assert_eq!(
        candidate.key_constraints[0].name.as_deref(),
        Some("renamed")
    );
    assert_eq!(candidate.key_constraints[0].columns, ["new_column"]);
    assert_eq!(candidate.key_constraints[1], added);
    assert_eq!(
        candidate.hierarchy.partition_inherited_key_constraints[0]
            .name
            .as_deref(),
        Some("renamed")
    );
}