qail-core 1.2.0

AST-native query builder - type-safe expressions, zero SQL strings
Documentation
use crate::ast::*;
use crate::parser::parse;

#[test]
fn test_parse_merge_update_insert() {
    let cmd = parse(
        "merge users as u using staging_users as s on u.id = s.id \
         when matched and u.name != s.name then update set name = s.name, email = s.email \
         when not matched then insert (id, name, email) values (s.id, s.name, s.email)",
    )
    .unwrap();

    assert_eq!(cmd.action, Action::Merge);
    assert_eq!(cmd.table, "users");

    let merge = cmd.merge.unwrap();
    assert_eq!(merge.target_alias.as_deref(), Some("u"));
    assert_eq!(
        merge.source,
        MergeSource::Table {
            name: "staging_users".to_string(),
            alias: Some("s".to_string()),
        }
    );
    assert_eq!(merge.on.len(), 1);
    assert_eq!(merge.on[0].left, Expr::Named("u.id".to_string()));
    assert_eq!(merge.on[0].value, Value::Column("s.id".to_string()));
    assert_eq!(merge.clauses.len(), 2);

    assert_eq!(merge.clauses[0].match_kind, MergeMatchKind::Matched);
    assert_eq!(merge.clauses[0].condition.len(), 1);
    match &merge.clauses[0].action {
        MergeAction::Update { assignments } => {
            assert_eq!(assignments.len(), 2);
            assert_eq!(assignments[0].0, "name");
            assert_eq!(assignments[0].1, Expr::Named("s.name".to_string()));
        }
        other => panic!("expected update action, got {other:?}"),
    }

    assert_eq!(
        merge.clauses[1].match_kind,
        MergeMatchKind::NotMatchedByTarget
    );
    match &merge.clauses[1].action {
        MergeAction::Insert { columns, values } => {
            assert_eq!(columns, &["id", "name", "email"]);
            assert_eq!(values[2], Expr::Named("s.email".to_string()));
        }
        other => panic!("expected insert action, got {other:?}"),
    }
}

#[test]
fn test_parse_merge_by_source_delete() {
    let cmd = parse(
        "merge users using staging_users on users.id = staging_users.id \
         when not matched by source then delete",
    )
    .unwrap();

    let merge = cmd.merge.unwrap();
    assert_eq!(
        merge.clauses[0].match_kind,
        MergeMatchKind::NotMatchedBySource
    );
    assert_eq!(merge.clauses[0].action, MergeAction::Delete);
}