vantage-vista 2.0.0

Universal, schema-bearing data handle for the Vantage data framework
Documentation
use super::*;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct DummyTable {
    dummy: DummyTableBlock,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
#[serde(deny_unknown_fields)]
struct DummyTableBlock {
    path: String,
}

type DummySpec = VistaSpec<DummyTable, NoExtras, NoExtras>;

#[test]
fn parses_minimal_spec() {
    let yaml = r#"
name: clients
columns:
  id:
    type: int
    flags: [id]
  name:
    type: string
    flags: [title, searchable]
dummy:
  path: data/clients.csv
"#;
    let spec: DummySpec = serde_yaml_ng::from_str(yaml).unwrap();
    assert_eq!(spec.name, "clients");
    assert_eq!(spec.columns.len(), 2);
    assert_eq!(spec.columns["id"].col_type.as_deref(), Some("int"));
    assert_eq!(
        spec.columns["name"].flags,
        vec![ColumnFlag::Title, ColumnFlag::Searchable]
    );
    assert_eq!(spec.driver.dummy.path, "data/clients.csv");
}

#[test]
fn rejects_unknown_driver_field() {
    let yaml = r#"
name: clients
columns:
  id: { type: int }
dummy:
  path: x
  bogus: 1
"#;
    let err = serde_yaml_ng::from_str::<DummySpec>(yaml).unwrap_err();
    assert!(
        err.to_string().contains("bogus") || err.to_string().contains("unknown"),
        "expected typo-detecting error, got: {err}"
    );
}

#[test]
fn reference_sugar_round_trip() {
    let yaml = r#"
name: clients
columns:
  shop_id:
    type: int
    references: shops
dummy:
  path: x
"#;
    let spec: DummySpec = serde_yaml_ng::from_str(yaml).unwrap();
    match spec.columns["shop_id"].references.as_ref().unwrap() {
        ReferenceSugar::Sugar(s) => assert_eq!(s, "shops"),
        other => panic!("expected sugar, got {other:?}"),
    }
}

#[test]
fn contained_section_round_trip() {
    let yaml = r#"
name: order
columns:
  id: { type: string, flags: [id] }
  lines: { type: string }
contained:
  lines:
    host_column: lines
    kind: contains_many
    id_column: line_id
    columns:
      line_id: { type: string, flags: [id] }
      product: { type: string }
      quantity: { type: int }
dummy:
  path: x
"#;
    let spec: DummySpec = serde_yaml_ng::from_str(yaml).unwrap();
    let c = &spec.contained["lines"];
    assert_eq!(c.host_column, "lines");
    assert_eq!(c.kind, ReferenceKind::ContainsMany);
    assert_eq!(c.id_column.as_deref(), Some("line_id"));
    assert_eq!(c.columns.len(), 3);
    assert_eq!(c.columns["quantity"].col_type.as_deref(), Some("int"));
}

#[test]
fn spec_without_contained_still_parses() {
    let yaml = r#"
name: clients
columns:
  id: { type: int, flags: [id] }
dummy:
  path: x
"#;
    let spec: DummySpec = serde_yaml_ng::from_str(yaml).unwrap();
    assert!(spec.contained.is_empty());
}

#[test]
fn full_reference_form() {
    let yaml = r#"
name: orders
columns:
  user_id:
    type: int
    references:
      table: users
      kind: has_one
      foreign_key: user_id
dummy:
  path: x
"#;
    let spec: DummySpec = serde_yaml_ng::from_str(yaml).unwrap();
    match spec.columns["user_id"].references.as_ref().unwrap() {
        ReferenceSugar::Full(r) => {
            assert_eq!(r.table, "users");
            assert_eq!(r.kind, ReferenceKind::HasOne);
            assert_eq!(r.foreign_key.as_deref(), Some("user_id"));
        }
        other => panic!("expected full, got {other:?}"),
    }
}

#[test]
fn a_new_spec_declares_only_its_name() {
    let spec = DummySpec::new("clients");
    assert_eq!(spec.name, "clients");
    assert!(spec.datasource.is_none() && spec.id_column.is_none());
    assert!(spec.columns.is_empty() && spec.references.is_empty() && spec.contained.is_empty());
    assert_eq!(spec.driver, DummyTable::default());
}

#[cfg(feature = "rhai")]
#[test]
fn a_lazy_column_keeps_its_declared_type_or_none() {
    let yaml = r#"
name: files
columns:
  lines: { type: int, lazy: "1" }
  shout: { lazy: "\"hi\"" }
dummy:
  path: x
"#;
    let spec: DummySpec = serde_yaml_ng::from_str(yaml).unwrap();
    let typed = spec.columns["lines"].lazy_column("lines").unwrap().unwrap();
    assert_eq!(typed.original_type.as_deref(), Some("int"));
    let untyped = spec.columns["shout"].lazy_column("shout").unwrap().unwrap();
    assert_eq!(untyped.original_type, None);
}