assert-migrator-reversible 6.2.0

For testing if Sea Orm Migrators are reversible
Documentation
use ::sea_orm_migration::sea_orm::QueryResult;
use ::sea_orm_migration::sea_orm::TryGetable;
use ::std::fmt::Debug;
use ::std::fmt::Write;

use super::TableSchema;

pub const QUERY_TABLE_SCHEMA_SQL: &'static str = &r#"
  SELECT
      table_name,
      column_name,
      is_nullable,
      data_type,
      character_maximum_length,
      character_octet_length,
      numeric_precision,
      numeric_precision_radix,
      numeric_scale,
      datetime_precision,
      interval_type,
      interval_precision,
      character_set_catalog,
      character_set_schema,
      character_set_name,
      collation_catalog,
      collation_schema,
      collation_name,
      domain_catalog,
      domain_schema,
      domain_name,
      udt_catalog,
      udt_schema,
      udt_name,
      scope_catalog,
      scope_schema,
      scope_name,
      maximum_cardinality,
      is_self_referencing,
      is_identity,
      identity_generation,
      identity_start,
      identity_increment,
      identity_maximum,
      identity_minimum,
      identity_cycle,
      is_generated,
      generation_expression,
      is_updatable
  FROM information_schema.columns
  WHERE table_schema not in ('pg_catalog', 'information_schema')
  AND table_name != 'seaql_migrations'
  ORDER BY table_name, column_name
"#;

pub fn build_table_schema(table_results: Vec<QueryResult>) -> Vec<TableSchema> {
    let mut all_table_schemas: Vec<TableSchema> = Vec::new();

    let last_schema = table_results.into_iter().fold(
        None as Option<TableSchema>,
        |maybe_table_schema, table_result| {
            let name = table_result
                .try_get::<String>("", "table_name")
                .expect("expect `table_name` to be present in SQL Query results");

            if let Some(mut table_schema) = maybe_table_schema {
                if table_schema.name != name {
                    let mut temp = TableSchema {
                        name,
                        schema: String::new(),
                    };
                    ::std::mem::swap(&mut temp, &mut table_schema);
                    all_table_schemas.push(temp);
                }

                collect_table_schema_parts_postgres(&mut table_schema.schema, table_result);
                return Some(table_schema);
            } else {
                let mut table_schema = match maybe_table_schema {
                    None => TableSchema {
                        name,
                        schema: String::new(),
                    },
                    Some(t_schema) => t_schema,
                };

                collect_table_schema_parts_postgres(&mut table_schema.schema, table_result);
                return Some(table_schema);
            }
        },
    );

    if last_schema.is_some() {
        all_table_schemas.push(last_schema.unwrap());
    }

    all_table_schemas
}

///
fn collect_table_schema_parts_postgres(dest: &mut String, table_result: QueryResult) {
    add_schema_part::<String>(dest, &table_result, &"column_name");
    add_schema_part::<String>(dest, &table_result, &"is_nullable");
    add_schema_part::<String>(dest, &table_result, &"data_type");
    add_schema_part::<Option<i32>>(dest, &table_result, &"character_maximum_length");
    add_schema_part::<Option<i32>>(dest, &table_result, &"character_octet_length");
    add_schema_part::<Option<i32>>(dest, &table_result, &"numeric_precision");
    add_schema_part::<Option<i32>>(dest, &table_result, &"numeric_precision_radix");
    add_schema_part::<Option<i32>>(dest, &table_result, &"numeric_scale");
    add_schema_part::<Option<i32>>(dest, &table_result, &"datetime_precision");
    add_schema_part::<Option<String>>(dest, &table_result, &"interval_type");
    add_schema_part::<Option<i32>>(dest, &table_result, &"interval_precision");
    add_schema_part::<Option<String>>(dest, &table_result, &"character_set_catalog");
    add_schema_part::<Option<String>>(dest, &table_result, &"character_set_schema");
    add_schema_part::<Option<String>>(dest, &table_result, &"character_set_name");
    add_schema_part::<Option<String>>(dest, &table_result, &"collation_catalog");
    add_schema_part::<Option<String>>(dest, &table_result, &"collation_schema");
    add_schema_part::<Option<String>>(dest, &table_result, &"collation_name");
    add_schema_part::<Option<String>>(dest, &table_result, &"domain_catalog");
    add_schema_part::<Option<String>>(dest, &table_result, &"domain_schema");
    add_schema_part::<Option<String>>(dest, &table_result, &"domain_name");
    add_schema_part::<Option<String>>(dest, &table_result, &"udt_catalog");
    add_schema_part::<Option<String>>(dest, &table_result, &"udt_schema");
    add_schema_part::<Option<String>>(dest, &table_result, &"udt_name");
    add_schema_part::<Option<String>>(dest, &table_result, &"scope_catalog");
    add_schema_part::<Option<String>>(dest, &table_result, &"scope_schema");
    add_schema_part::<Option<String>>(dest, &table_result, &"scope_name");
    add_schema_part::<Option<i32>>(dest, &table_result, &"maximum_cardinality");
    add_schema_part::<Option<String>>(dest, &table_result, &"is_self_referencing");
    add_schema_part::<Option<String>>(dest, &table_result, &"is_identity");
    add_schema_part::<Option<String>>(dest, &table_result, &"identity_generation");
    add_schema_part::<Option<String>>(dest, &table_result, &"identity_start");
    add_schema_part::<Option<String>>(dest, &table_result, &"identity_increment");
    add_schema_part::<Option<String>>(dest, &table_result, &"identity_maximum");
    add_schema_part::<Option<String>>(dest, &table_result, &"identity_minimum");
    add_schema_part::<Option<String>>(dest, &table_result, &"identity_cycle");
    add_schema_part::<Option<String>>(dest, &table_result, &"is_generated");
    add_schema_part::<Option<String>>(dest, &table_result, &"generation_expression");
    add_schema_part::<Option<String>>(dest, &table_result, &"is_updatable");
}

fn add_schema_part<T>(schema: &mut String, table_result: &QueryResult, column_name: &str)
where
    T: TryGetable + Debug,
{
    let part: T = table_result
        .try_get::<T>("", column_name)
        .expect("expect to be able to unwrap column");

    write!(schema, ", {:?}", part).expect("Writing to schema should work");
}