Skip to content

Commit

Permalink
fix references in sqlite (#1151)
Browse files Browse the repository at this point in the history
  • Loading branch information
jondot authored Jan 8, 2025
1 parent 6fe90ea commit f12653a
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 36 deletions.
2 changes: 2 additions & 0 deletions loco-gen/src/templates/migration/add_references.t
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,7 @@ impl MigrationTrait for Migration {
{% for column in columns -%}
remove_column(m, "{{plural_snake}}", "{{column.0}}").await?;
{% endfor -%}

Ok(())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ impl MigrationTrait for Migration {

async fn down(&self, m: &SchemaManager) -> Result<(), DbErr> {
remove_reference(m, "posts", "user", "").await?;
}
Ok(())
}
}
6 changes: 1 addition & 5 deletions loco-new/tests/wizard/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ fn test_combination(
tester.run_generate_migration(&vec![
"CreatePosts",
"title:string",
"user:references",
"movies:references",
]);

Expand All @@ -208,10 +207,7 @@ fn test_combination(
]);

// Generate AddUserRefToPosts migration
// TODO:: not working on sqlite.
// - thread 'main' panicked at 'Sqlite doesn't support multiple alter options'
// - Sqlite does not support modification of foreign key constraints to existing
// tester.run_generate_migration(&vec!["AddUserRefToPosts", "movies:references"]);
tester.run_generate_migration(&vec!["AddUserRefToPosts", "users:references"]);

// Generate CreateJoinTableUsersAndGroups migration
tester.run_generate_migration(&vec!["CreateJoinTableUsersAndGroups", "count:int"]);
Expand Down
98 changes: 68 additions & 30 deletions src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,29 +412,57 @@ pub async fn add_reference(
} else {
refname.to_string()
};
// from movies to users -> movies#user_id to users#id
m.alter_table(
alter(Alias::new(&nz_fromtbl))
// add movies#user_id (the user_id column is new)
.add_column(ColType::Integer.to_def(Alias::new(&nz_ref_name))) // XXX fix, totbl_id
// add fk on movies#user_id
.add_foreign_key(
&TableForeignKey::new()
// fk-movies-user_id-to-users
.name(format!("fk-{nz_fromtbl}-{nz_ref_name}-to-{nz_totbl}"))
// from movies#user_id
.from_tbl(Alias::new(nz_fromtbl))
.from_col(Alias::new(&nz_ref_name)) // xxx fix
// to users#id
.to_tbl(Alias::new(nz_totbl))
.to_col(Alias::new("id"))
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
let bk = m.get_database_backend();
let col = ColType::Integer.to_def(Alias::new(&nz_ref_name));
let fk = TableForeignKey::new()
// fk-movies-user_id-to-users
.name(format!("fk-{nz_fromtbl}-{nz_ref_name}-to-{nz_totbl}"))
// from movies#user_id
.from_tbl(Alias::new(&nz_fromtbl))
.from_col(Alias::new(&nz_ref_name)) // xxx fix
// to users#id
.to_tbl(Alias::new(nz_totbl))
.to_col(Alias::new("id"))
.on_delete(ForeignKeyAction::Cascade)
.on_update(ForeignKeyAction::Cascade)
.to_owned();
match bk {
sea_orm::DatabaseBackend::MySql | sea_orm::DatabaseBackend::Postgres => {
// from movies to users -> movies#user_id to users#id
m.alter_table(
alter(Alias::new(&nz_fromtbl))
// add movies#user_id (the user_id column is new)
.add_column(col.clone()) // XXX fix, totbl_id
// add fk on movies#user_id
.add_foreign_key(&fk)
.to_owned(),
)
.to_owned(),
)
.await?;
.await?;
}
sea_orm::DatabaseBackend::Sqlite => {
// from movies to users -> movies#user_id to users#id
m.alter_table(
alter(Alias::new(&nz_fromtbl))
// add movies#user_id (the user_id column is new)
.add_column(col.clone()) // XXX fix, totbl_id
.to_owned(),
)
.await?;
// Per Rails 5.2, adding FK to existing table does nothing because
// sqlite will not allow it. FK in sqlite are applied only on table
// creation. more: https://www.bigbinary.com/blog/rails-6-adds-add_foreign_key-and-remove_foreign_key-for-sqlite3
// we comment it below leaving it for academic purposes.
/*
m.alter_table(
alter(Alias::new(&nz_fromtbl))
// add fk on movies#user_id
.add_foreign_key(&fk)
.to_owned(),
)
.await?;
*/
}
}
Ok(())
}

Expand Down Expand Up @@ -462,16 +490,26 @@ pub async fn remove_reference(
} else {
refname.to_string()
};
// from movies to users -> movies#user_id to users#id
m.alter_table(
alter(Alias::new(&nz_fromtbl))
.drop_foreign_key(
// fk-movies-user_id-to-users
Alias::new(format!("fk-{nz_fromtbl}-{nz_ref_name}-to-{nz_totbl}")),
let bk = m.get_database_backend();
match bk {
sea_orm::DatabaseBackend::MySql | sea_orm::DatabaseBackend::Postgres => {
// from movies to users -> movies#user_id to users#id
m.alter_table(
alter(Alias::new(&nz_fromtbl))
.drop_foreign_key(
// fk-movies-user_id-to-users
Alias::new(format!("fk-{nz_fromtbl}-{nz_ref_name}-to-{nz_totbl}")),
)
.to_owned(),
)
.to_owned(),
)
.await?;
.await?;
}
sea_orm::DatabaseBackend::Sqlite => {
// Per Rails 5.2, removing FK on existing table does nothing because
// sqlite will not allow it.
// more: https://www.bigbinary.com/blog/rails-6-adds-add_foreign_key-and-remove_foreign_key-for-sqlite3
}
}
Ok(())
}

Expand Down

0 comments on commit f12653a

Please sign in to comment.