sqldiff 0.5.0

primitives to auto-generate SQL schema migrations
Documentation
use openapiv3::{OpenAPI, SchemaKind, Schema as OaSchema, Type as OaType};
use convert_case::{Case, Casing};
use crate::schema::{Column, Table, Type};
use crate::Schema;

impl TryFrom<OpenAPI> for Schema {
    type Error = anyhow::Error;

    fn try_from(spec: OpenAPI) -> Result<Self, Self::Error> {
        let mut tables = Vec::new();
        if let Some(components) = &spec.components {
            for (schema_name, schema) in components.schemas.iter().filter(|(schema_name, schema)| {
                !schema_name.ends_with("Response")
            }) {
                let schema = schema.resolve(&spec);
                let columns = schema_to_columns(&schema, &spec)?;
                let name = schema_name.to_case(Case::Snake);
                let table = Table {
                    name: schema_name.to_case(Case::Snake),
                    columns,
                    indexes: vec![]
                };
                tables.push(table);
            }
        }
        Ok(Schema {
            tables,
        })
    }
}

fn schema_to_type(schema: &OaSchema, spec:&OpenAPI) -> anyhow::Result<Type> {
    match schema.schema_kind {
        SchemaKind::Type(OaType::String(_)) => {
            Ok(Type::Text)
        }
        SchemaKind::Type(OaType::Integer(_)) => {
            Ok(Type::Integer)
        }
        SchemaKind::Type(OaType::Boolean{..}) => {
            Ok(Type::Boolean)
        }
        SchemaKind::Type(OaType::Number(_)) => {
            Ok(Type::Numeric)
        }
        _ => panic!("Unsupported type: {:?}", schema)
    }
}

fn schema_to_columns(schema: &OaSchema, spec: &OpenAPI) -> anyhow::Result<Vec<Column>> {
    let mut columns = vec![];
    let props = schema.properties().ok_or(anyhow::anyhow!("No properties"))?;
    for (name, prop) in props.into_iter() {
        let prop = prop.resolve(spec);
        let column = Column {
            primary_key: false,
            name: name.to_case(Case::Snake),
            typ: schema_to_type(prop, spec)?,
            nullable: prop.required(&name),
            default: None,
        };
        columns.push(column);
    }
    Ok(columns)
}