ormdantic-schema 2.0.1

Schema metadata structures for Ormdantic
Documentation
use ormdantic_core::TableId;
use ormdantic_schema::{
    CheckConstraintDef, ColumnDef, ExclusionConstraintDef, ExclusionElementDef, FieldKind,
    ForeignKeyDef, IndexDef, MysqlTableOptions, OracleTableCompression, RelationshipCardinality,
    RelationshipDef, TableDef, UniqueConstraintDef,
};

#[test]
fn table_new_builds_unknown_columns() {
    let table = TableDef::new("flavor", "id", vec!["id".to_string(), "name".to_string()]);

    assert_eq!(table.model_key(), "flavor");
    assert_eq!(table.name(), "flavor");
    assert_eq!(table.primary_key(), "id");
    assert_eq!(table.column_names().collect::<Vec<_>>(), vec!["id", "name"]);
    assert!(table
        .columns()
        .iter()
        .all(|column| column.kind() == &FieldKind::Unknown));
}

#[test]
fn table_from_parts_exposes_metadata_and_qualified_name() {
    let relationship =
        RelationshipDef::new("supplier", "supplier", "id", RelationshipCardinality::One);
    let mut table = TableDef::from_parts(
        "flavor",
        "Flavor",
        "id",
        vec![
            ColumnDef::new("id", FieldKind::Integer).primary_key(true),
            ColumnDef::new("supplier_id", FieldKind::Integer),
        ],
        vec![IndexDef::new(
            "flavor_supplier_idx",
            vec!["supplier_id".to_string()],
        )],
        vec![UniqueConstraintDef::new(
            "flavor_supplier_unique",
            vec!["supplier_id".to_string()],
        )],
        vec![relationship],
    )
    .with_schema("inventory")
    .with_comment("flavor table")
    .with_tablespace("fastspace")
    .with_mysql_engine("InnoDB")
    .with_mysql_charset("utf8mb4")
    .with_mysql_collation("utf8mb4_unicode_ci")
    .with_mysql_row_format("DYNAMIC")
    .with_mysql_key_block_size(8)
    .with_mysql_pack_keys(true)
    .with_mysql_checksum(true)
    .with_mysql_delay_key_write(true)
    .with_mysql_stats_persistent(true)
    .with_mysql_stats_auto_recalc(false)
    .with_mysql_stats_sample_pages(32)
    .with_mysql_avg_row_length(64)
    .with_mysql_max_rows(1000)
    .with_mysql_min_rows(10)
    .with_mysql_insert_method("LAST")
    .with_mysql_data_directory("/var/lib/mysql/data")
    .with_mysql_index_directory("/var/lib/mysql/index")
    .with_mysql_connection("mysql://remote.example/db/flavor")
    .with_mysql_union(vec!["flavor_hot".to_string(), "flavor_cold".to_string()])
    .with_mysql_partition_by("HASH (id)")
    .with_mysql_partitions(4)
    .with_mysql_subpartition_by("KEY (supplier_id)")
    .with_mysql_subpartitions(2)
    .with_mysql_auto_increment(101)
    .with_postgres_inherits(vec!["base_flavor".to_string()])
    .with_postgres_with(vec![("fillfactor".to_string(), "70".to_string())])
    .with_postgres_using("heap")
    .postgres_unlogged()
    .sqlite_strict()
    .sqlite_without_rowid()
    .with_oracle_compress_level(6)
    .with_postgres_partition_by("RANGE (id)")
    .with_check_constraints(vec![
        CheckConstraintDef::new("supplier_id > 0").named("supplier_check")
    ])
    .with_foreign_keys(vec![ForeignKeyDef::new(
        vec!["supplier_id".to_string()],
        "supplier",
        vec!["id".to_string()],
    )])
    .with_exclusion_constraints(vec![ExclusionConstraintDef::new(
        "flavor_supplier_exclusion",
        vec![ExclusionElementDef::column("supplier_id", "=")],
    )]);
    table.set_id(TableId(7));

    assert_eq!(table.id(), Some(TableId(7)));
    assert_eq!(table.model_key(), "Flavor");
    assert_eq!(table.schema(), Some("inventory"));
    assert_eq!(table.comment(), Some("flavor table"));
    assert_eq!(table.tablespace(), Some("fastspace"));
    assert_eq!(table.mysql_engine(), Some("InnoDB"));
    assert_eq!(table.mysql_charset(), Some("utf8mb4"));
    assert_eq!(table.mysql_collation(), Some("utf8mb4_unicode_ci"));
    assert_eq!(table.mysql_row_format(), Some("DYNAMIC"));
    assert_eq!(table.mysql_key_block_size(), Some(8));
    assert_eq!(table.mysql_pack_keys(), Some(true));
    assert_eq!(table.mysql_checksum(), Some(true));
    assert_eq!(table.mysql_delay_key_write(), Some(true));
    assert_eq!(table.mysql_stats_persistent(), Some(true));
    assert_eq!(table.mysql_stats_auto_recalc(), Some(false));
    assert_eq!(table.mysql_stats_sample_pages(), Some(32));
    assert_eq!(table.mysql_avg_row_length(), Some(64));
    assert_eq!(table.mysql_max_rows(), Some(1000));
    assert_eq!(table.mysql_min_rows(), Some(10));
    assert_eq!(table.mysql_insert_method(), Some("LAST"));
    assert_eq!(table.mysql_data_directory(), Some("/var/lib/mysql/data"));
    assert_eq!(table.mysql_index_directory(), Some("/var/lib/mysql/index"));
    assert_eq!(
        table.mysql_connection(),
        Some("mysql://remote.example/db/flavor")
    );
    assert_eq!(
        table.mysql_union(),
        &["flavor_hot".to_string(), "flavor_cold".to_string()]
    );
    assert_eq!(table.mysql_partition_by(), Some("HASH (id)"));
    assert_eq!(table.mysql_partitions(), Some(4));
    assert_eq!(table.mysql_subpartition_by(), Some("KEY (supplier_id)"));
    assert_eq!(table.mysql_subpartitions(), Some(2));
    assert_eq!(table.mysql_auto_increment(), Some(101));
    assert_eq!(table.postgres_inherits(), &["base_flavor".to_string()]);
    assert_eq!(
        table.postgres_with(),
        &[("fillfactor".to_string(), "70".to_string())]
    );
    assert_eq!(table.postgres_using(), Some("heap"));
    assert!(table.is_postgres_unlogged());
    assert!(table.is_sqlite_strict());
    assert!(table.is_sqlite_without_rowid());
    assert_eq!(
        table.oracle_compress(),
        Some(&OracleTableCompression::Level(6))
    );
    assert_eq!(table.postgres_partition_by(), Some("RANGE (id)"));
    assert_eq!(table.qualified_name().to_string(), "inventory.flavor");
    assert_eq!(table.indexes().len(), 1);
    assert_eq!(table.unique_constraints().len(), 1);
    assert_eq!(table.relationships().len(), 1);
    assert_eq!(table.check_constraints().len(), 1);
    assert_eq!(table.foreign_keys().len(), 1);
    assert_eq!(table.exclusion_constraints().len(), 1);
}

#[test]
fn table_exposes_postgres_child_partition_metadata() {
    let table = TableDef::from_parts(
        "flavor_2026",
        "Flavor2026",
        "id",
        vec![ColumnDef::new("id", FieldKind::Integer).primary_key(true)],
        Vec::new(),
        Vec::new(),
        Vec::new(),
    )
    .with_postgres_partition_of("flavor")
    .with_postgres_partition_for("FOR VALUES FROM (2026) TO (2027)");

    assert_eq!(table.postgres_partition_of(), Some("flavor"));
    assert_eq!(
        table.postgres_partition_for(),
        Some("FOR VALUES FROM (2026) TO (2027)")
    );
}

#[test]
fn table_bulk_and_option_builders_expose_all_optional_metadata() {
    let options = MysqlTableOptions {
        engine: Some("InnoDB".to_string()),
        charset: Some("utf8mb4".to_string()),
        collation: Some("utf8mb4_bin".to_string()),
        row_format: Some("COMPRESSED".to_string()),
        key_block_size: Some(4),
        pack_keys: Some(false),
        checksum: Some(true),
        delay_key_write: Some(false),
        stats_persistent: Some(true),
        stats_auto_recalc: Some(true),
        stats_sample_pages: Some(8),
        avg_row_length: Some(128),
        max_rows: Some(10_000),
        min_rows: Some(100),
        insert_method: Some("FIRST".to_string()),
        data_directory: Some("/data".to_string()),
        index_directory: Some("/index".to_string()),
        connection: Some("mysql://remote/flavor".to_string()),
        union: vec!["archive".to_string()],
        partition_by: Some("HASH(id)".to_string()),
        partitions: Some(8),
        subpartition_by: Some("KEY(id)".to_string()),
        subpartitions: Some(4),
        auto_increment: Some(500),
    };

    let table = TableDef::new("flavor", "id", vec!["id".to_string()])
        .with_mysql_options(options)
        .with_postgres_using_option(Some("zheap".to_string()))
        .with_postgres_unlogged(false)
        .with_sqlite_strict(false)
        .with_sqlite_without_rowid(false)
        .with_oracle_compress()
        .with_oracle_compress_option(Some(OracleTableCompression::Enabled))
        .with_mssql_primary_key_nonclustered(true)
        .with_postgres_partition_by_option(Some("LIST(id)".to_string()))
        .with_postgres_partition_of_option(Some("parent".to_string()))
        .with_postgres_partition_for_option(Some("FOR VALUES IN (1)".to_string()));

    assert_eq!(table.mysql_engine(), Some("InnoDB"));
    assert_eq!(table.mysql_charset(), Some("utf8mb4"));
    assert_eq!(table.mysql_collation(), Some("utf8mb4_bin"));
    assert_eq!(table.mysql_row_format(), Some("COMPRESSED"));
    assert_eq!(table.mysql_key_block_size(), Some(4));
    assert_eq!(table.mysql_pack_keys(), Some(false));
    assert_eq!(table.mysql_checksum(), Some(true));
    assert_eq!(table.mysql_delay_key_write(), Some(false));
    assert_eq!(table.mysql_stats_persistent(), Some(true));
    assert_eq!(table.mysql_stats_auto_recalc(), Some(true));
    assert_eq!(table.mysql_stats_sample_pages(), Some(8));
    assert_eq!(table.mysql_avg_row_length(), Some(128));
    assert_eq!(table.mysql_max_rows(), Some(10_000));
    assert_eq!(table.mysql_min_rows(), Some(100));
    assert_eq!(table.mysql_insert_method(), Some("FIRST"));
    assert_eq!(table.mysql_data_directory(), Some("/data"));
    assert_eq!(table.mysql_index_directory(), Some("/index"));
    assert_eq!(table.mysql_connection(), Some("mysql://remote/flavor"));
    assert_eq!(table.mysql_union(), &["archive".to_string()]);
    assert_eq!(table.mysql_partition_by(), Some("HASH(id)"));
    assert_eq!(table.mysql_partitions(), Some(8));
    assert_eq!(table.mysql_subpartition_by(), Some("KEY(id)"));
    assert_eq!(table.mysql_subpartitions(), Some(4));
    assert_eq!(table.mysql_auto_increment(), Some(500));
    assert_eq!(table.postgres_using(), Some("zheap"));
    assert!(!table.is_postgres_unlogged());
    assert!(!table.is_sqlite_strict());
    assert!(!table.is_sqlite_without_rowid());
    assert_eq!(
        table.oracle_compress(),
        Some(&OracleTableCompression::Enabled)
    );
    assert!(table.is_mssql_primary_key_nonclustered());
    assert_eq!(table.postgres_partition_by(), Some("LIST(id)"));
    assert_eq!(table.postgres_partition_of(), Some("parent"));
    assert_eq!(table.postgres_partition_for(), Some("FOR VALUES IN (1)"));
}