diff --git a/diesel_cli/src/infer_schema_internals/sqlite.rs b/diesel_cli/src/infer_schema_internals/sqlite.rs index 3fc16779abdf..272a462c10e2 100644 --- a/diesel_cli/src/infer_schema_internals/sqlite.rs +++ b/diesel_cli/src/infer_schema_internals/sqlite.rs @@ -114,6 +114,13 @@ fn get_sqlite_version(conn: &mut SqliteConnection) -> QueryResult Ok(SqliteVersion::new(parts[0], parts[1], parts[2])) } +// In sqlite the rowid is a signed 64-bit integer. +// See: https://sqlite.org/rowidtable.html +// We should use BigInt here but to avoid type problems with foreign keys to +// rowid columns this is for now not done. A patch can be used after the schema +// is generated to convert the columns to BigInt as needed. +const ROWID_TYPE_NAME: &str = "Integer"; + pub fn get_table_data( conn: &mut SqliteConnection, table: &TableName, @@ -134,6 +141,27 @@ pub fn get_table_data( // See: https://github.com/diesel-rs/diesel/issues/3579 as to why we use a direct // `sql_query` with `QueryableByName` instead of using `sql::`. let mut result = sql_query(query).load::(conn)?; + // Add implicit rowid primary key column if the only primary key is rowid + // and ensure that the rowid column uses the right type. + let primary_key = get_primary_keys(conn, table)?; + if primary_key.len() == 1 { + let primary_key = primary_key.first().expect("guaranteed to have one element"); + if !result.iter_mut().any(|x| &x.column_name == primary_key) { + // Prepend implicit rowid column for the rowid implicit primary key. + result.insert( + 0, + ColumnInformation { + column_name: String::from(primary_key), + type_name: String::from(ROWID_TYPE_NAME), + type_schema: None, + nullable: false, + max_length: None, + comment: None, + }, + ); + } + } + match column_sorting { ColumnSorting::OrdinalPosition => {} ColumnSorting::Name => { diff --git a/diesel_cli/tests/print_schema.rs b/diesel_cli/tests/print_schema.rs index cdbdd16cafd1..dd298713b81a 100644 --- a/diesel_cli/tests/print_schema.rs +++ b/diesel_cli/tests/print_schema.rs @@ -268,6 +268,12 @@ fn print_schema_sqlite_implicit_foreign_key_reference() { test_print_schema("print_schema_sqlite_implicit_foreign_key_reference", vec![]); } +#[test] +#[cfg(feature = "sqlite")] +fn print_schema_sqlite_without_explicit_primary_key() { + test_print_schema("print_schema_sqlite_without_explicit_primary_key", vec![]) +} + #[test] #[cfg(feature = "postgres")] fn print_schema_respects_type_name_case() { diff --git a/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/expected.snap b/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/expected.snap index 98bf663e0820..20ce77fb7a64 100644 --- a/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/expected.snap +++ b/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/expected.snap @@ -7,23 +7,85 @@ description: "Test: print_schema_sqlite_without_explicit_primary_key" diesel::table! { no_explicit (rowid) { rowid -> Integer, - name -> Text, + name -> Nullable, + } +} + +diesel::table! { + with_explicit_aliased_rowid (id) { + id -> Nullable, + name -> Nullable, + } +} + +diesel::table! { + with_explicit_aliased_rowid_not_null (id) { + id -> Integer, + name -> Nullable, + } +} + +diesel::table! { + with_explicit_pk_rowid (rowid) { + rowid -> Nullable, + name -> Nullable, + } +} + +diesel::table! { + with_explicit_pk_rowid_autoincrement (rowid) { + rowid -> Nullable, + name -> Nullable, + } +} + +diesel::table! { + with_explicit_pk_rowid_autoincrement_not_null (rowid) { + rowid -> Integer, + name -> Nullable, + } +} + +diesel::table! { + with_explicit_pk_rowid_not_null (rowid) { + rowid -> Integer, + name -> Nullable, } } diesel::table! { with_explicit_rowid (oid) { oid -> Integer, - name -> Text, - rowid -> Text, + name -> Nullable, + rowid -> Nullable, } } diesel::table! { with_explicit_rowid_oid (_rowid_) { _rowid_ -> Integer, - name -> Text, - rowid -> Text, - oid -> Text, + name -> Nullable, + rowid -> Nullable, + oid -> Nullable, } } + +diesel::table! { + without_rowid (word) { + word -> Text, + cnt -> Nullable, + } +} + +diesel::allow_tables_to_appear_in_same_query!( + no_explicit, + with_explicit_aliased_rowid, + with_explicit_aliased_rowid_not_null, + with_explicit_pk_rowid, + with_explicit_pk_rowid_autoincrement, + with_explicit_pk_rowid_autoincrement_not_null, + with_explicit_pk_rowid_not_null, + with_explicit_rowid, + with_explicit_rowid_oid, + without_rowid, +); diff --git a/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/schema.sql b/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/schema.sql index c9d457fdaf34..d4824367defe 100644 --- a/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/schema.sql +++ b/diesel_cli/tests/print_schema/print_schema_sqlite_without_explicit_primary_key/sqlite/schema.sql @@ -12,3 +12,38 @@ CREATE TABLE with_explicit_rowid_oid ( rowid TEXT, oid TEXT ); + +CREATE TABLE with_explicit_pk_rowid ( + rowid INTEGER PRIMARY KEY, + name TEXT +); + +CREATE TABLE with_explicit_pk_rowid_autoincrement ( + rowid INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT +); + +CREATE TABLE with_explicit_pk_rowid_not_null ( + rowid INTEGER PRIMARY KEY NOT NULL, + name TEXT +); + +CREATE TABLE with_explicit_pk_rowid_autoincrement_not_null ( + rowid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, + name TEXT +); + +CREATE TABLE with_explicit_aliased_rowid ( + id INTEGER PRIMARY KEY, + name TEXT +); + +CREATE TABLE with_explicit_aliased_rowid_not_null ( + id INTEGER PRIMARY KEY NOT NULL, + name TEXT +); + +CREATE TABLE without_rowid ( + word TEXT PRIMARY KEY, + cnt INTEGER +) WITHOUT ROWID;