Repository: diesel-rs/diesel
File: diesel_cli/src/infer_schema_internals/sqlite.rs (Rust)

Code before:
    let sqlite_version = get_sqlite_version(conn);
    let query = if sqlite_version >= SqliteVersion::new(3, 26, 0) {
        format!("PRAGMA TABLE_XINFO('{}')", &table.sql_name)
    } else {
        format!("PRAGMA TABLE_INFO('{}')", &table.sql_name)
    };
    let results = sql::<pragma_table_info::SqlType>(&query).load::<FullTableInfo>(conn)?;
    let mut collected: Vec<String> = results
        .into_iter()
        .filter_map(|i| if i.primary_key { Some(i.name) } else { None })
        .collect();
    if collected.is_empty() {
        collected.push("rowid".to_owned());
    }
    Ok(collected)
}

pub fn determine_column_type(
    attr: &ColumnInformation,
) -> Result<ColumnType, Box<dyn Error + Send + Sync + 'static>> {
    let mut type_name = attr.type_name.to_lowercase();
    if type_name == "generated always" {
        type_name.clear();
    }

    let path = if is_bool(&type_name) {
        String::from("Bool")
    } else if is_smallint(&type_name) {
        String::from("SmallInt")
    } else if is_bigint(&type_name) {
        String::from("BigInt")
    } else if type_name.contains("int") {
        String::from("Integer")
    } else if is_text(&type_name) {
        String::from("Text")
    } else if is_binary(&type_name) {
        String::from("Binary")
    } else if is_float(&type_name) {
        String::from("Float")
    } else if is_double(&type_name) {
        String::from("Double")
    } else if type_name == "datetime" || type_name == "timestamp" {
        String::from("Timestamp")
    } else if type_name == "date" {
        String::from("Date")
    } else if type_name == "time" {
        String::from("Time")
    } else {
        return Err(format!("Unsupported type: {type_name}").into());
    };


Review comment (suggestion):
I would like to see a comment here explaining that all sqlite tables either have a rowid or a primary key with a reference to the documentation.

Also we should likely check for the following cases: There is no other column named rowid for the table (if that's not the case fall back to the other variants shown in the documentation). Also that case likely should be covered with some additional test

Code after:

pub fn get_primary_keys(
    conn: &mut SqliteConnection,
    table: &TableName,
) -> QueryResult<Vec<String>> {
    let sqlite_version = get_sqlite_version(conn);
    let query = if sqlite_version >= SqliteVersion::new(3, 26, 0) {
        format!("PRAGMA TABLE_XINFO('{}')", &table.sql_name)
    } else {
        format!("PRAGMA TABLE_INFO('{}')", &table.sql_name)
    };
    let results = sql::<pragma_table_info::SqlType>(&query).load::<FullTableInfo>(conn)?;
    let mut collected: Vec<String> = results
        .iter()
        .filter_map(|i| {
            if i.primary_key {
                Some(i.name.clone())
            } else {
                None
            }
        })
        .collect();
    // SQLite tables without "WITHOUT ROWID" always have aliases for the implicit PRIMARY KEY "rowid" and its aliases
    // unless the user defines a column with those names, then the name in question refers to the created column
    // https://www.sqlite.org/rowidtable.html
    if collected.is_empty() {
        for alias in SQLITE_ROWID_ALIASES {
            if results.iter().any(|v| &v.name.as_str() == alias) {
                continue;
            }

            // only add one alias as the primary key
            collected.push(alias.to_string());
            break;
        }
        // if it is still empty at this point, then a "diesel requires a primary key" error will be given
    }
    Ok(collected)
}

pub fn determine_column_type(
    attr: &ColumnInformation,
) -> Result<ColumnType, Box<dyn Error + Send + Sync + 'static>> {
    let mut type_name = attr.type_name.to_lowercase();
    if type_name == "generated always" {
        type_name.clear();
    }

    let path = if is_bool(&type_name) {
        String::from("Bool")
    } else if is_smallint(&type_name) {