Skip to content

Commit d9ef425

Browse files
committed
quick fix!
discover hidden sqlite columns using raw query during sync
1 parent 50ef02c commit d9ef425

1 file changed

Lines changed: 28 additions & 59 deletions

File tree

src/schema/builder.rs

Lines changed: 28 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use super::{Schema, TopologicalSort};
22
use crate::{ConnectionTrait, DbBackend, DbErr, EntityTrait, Statement};
33
use sea_query::{
4-
ForeignKeyCreateStatement, Index, IndexCreateStatement, IntoIden, TableAlterStatement,
5-
TableCreateStatement, TableName, TableRef, extension::postgres::TypeCreateStatement,
4+
ForeignKeyCreateStatement, IndexCreateStatement, TableAlterStatement, TableCreateStatement,
5+
TableName, TableRef, extension::postgres::TypeCreateStatement,
66
};
77

88
/// A schema builder that can take a registry of Entities and synchronize it with database.
@@ -322,7 +322,32 @@ impl EntitySchemaInfo {
322322
break;
323323
}
324324
}
325+
325326
if !column_exists {
327+
#[cfg(feature = "rusqlite")]
328+
{
329+
// TODO: sea_scheme has a bug. this is a quick fix
330+
// On SQLite, PRAGMA table_info does not return generated/virtual columns.
331+
if column_def.get_column_spec().extra.is_some() {
332+
let tbl_str = table_name.1.to_string();
333+
let col_name = column_def.get_column_name();
334+
// hidden IN (2, 3) - filters to only hidden generated columns:
335+
// 2 = Hidden generated column (computed, not stored)
336+
// 3 = Hidden stored generated column (computed and stored)
337+
let xinfo_sql = format!(
338+
"SELECT name FROM pragma_table_xinfo('{}') WHERE name = '{}' AND hidden IN (2, 3)",
339+
tbl_str.replace('\'', "''"),
340+
col_name.replace('\'', "''")
341+
);
342+
let rows = db
343+
.query_all_raw(Statement::from_string(DbBackend::Sqlite, xinfo_sql))
344+
.await?;
345+
if !rows.is_empty() {
346+
continue; // Column exists actually
347+
}
348+
}
349+
}
350+
326351
let mut renamed_from = "";
327352
if let Some(comment) = &column_def.get_column_spec().comment {
328353
if let Some((_, suffix)) = comment.rsplit_once("renamed_from \"") {
@@ -351,6 +376,7 @@ impl EntitySchemaInfo {
351376
}
352377
}
353378
}
379+
354380
if db.get_database_backend() != DbBackend::Sqlite {
355381
for foreign_key in self.table.get_foreign_key_create_stmts().iter() {
356382
let mut key_exists = false;
@@ -387,46 +413,6 @@ impl EntitySchemaInfo {
387413
db.execute(&stmt).await?;
388414
}
389415
}
390-
if let Some(existing_table) = existing_table {
391-
// For columns with a column-level UNIQUE constraint (#[sea_orm(unique)]) that
392-
// already exist in the table but do not yet have a unique index, create one.
393-
for column_def in self.table.get_columns() {
394-
if column_def.get_column_spec().unique {
395-
let col_name = column_def.get_column_name();
396-
let col_exists = existing_table
397-
.get_columns()
398-
.iter()
399-
.any(|c| c.get_column_name() == col_name);
400-
if !col_exists {
401-
// Column is being added in this sync pass; the ALTER TABLE ADD COLUMN
402-
// will include the UNIQUE inline, so no separate index needed.
403-
continue;
404-
}
405-
let already_unique = existing_table.get_indexes().iter().any(|idx| {
406-
if !idx.is_unique_key() {
407-
return false;
408-
}
409-
let cols = idx.get_index_spec().get_column_names();
410-
cols.len() == 1 && cols[0] == col_name
411-
});
412-
if !already_unique {
413-
let table_name =
414-
self.table.get_table_name().expect("table must have a name");
415-
let tbl_str = table_name.sea_orm_table().to_string();
416-
let table_ref = table_name.clone();
417-
db.execute(
418-
Index::create()
419-
.name(format!("idx-{tbl_str}-{col_name}"))
420-
.table(table_ref)
421-
.col(col_name.into_iden())
422-
.unique()
423-
.if_not_exists(),
424-
)
425-
.await?;
426-
}
427-
}
428-
}
429-
}
430416
if let Some(existing_table) = existing_table {
431417
// find all unique keys from existing table
432418
// if it no longer exist in new schema, drop it
@@ -441,23 +427,6 @@ impl EntitySchemaInfo {
441427
break;
442428
}
443429
}
444-
// Also check if the unique index corresponds to a column-level UNIQUE
445-
// constraint (from #[sea_orm(unique)]). These are embedded in the CREATE
446-
// TABLE column definition and not tracked in self.indexes, so we must not
447-
// try to drop them during sync.
448-
if !has_index {
449-
let index_cols = existing_index.get_index_spec().get_column_names();
450-
if index_cols.len() == 1 {
451-
for column_def in self.table.get_columns() {
452-
if column_def.get_column_name() == index_cols[0]
453-
&& column_def.get_column_spec().unique
454-
{
455-
has_index = true;
456-
break;
457-
}
458-
}
459-
}
460-
}
461430
if !has_index {
462431
if let Some(drop_existing) = existing_index.get_index_spec().get_name() {
463432
db.execute(sea_query::Index::drop().name(drop_existing))

0 commit comments

Comments
 (0)