-
-
Notifications
You must be signed in to change notification settings - Fork 614
Description
Following a helpful discussion on Discord I would like to code an upgrade to sea-orm-cli generate entity, if the project is willing to merge a pull request.
My idea is that when an entity is regenerated the custom sections of code that we have written should not be lost.
My experience, so far, is only with modifying impl ActiveModelBehavior for ActiveModel {}
but I imagine there will be other areas, such as Relations, where we will want modifications to be kept when the entity is regenerated.
I am not proposing adding great intelligence, so it will not remove the need for manual changes if the database schema changes. However, it would save manual work at present without enforcing fixed conventions around how the code base is organised.
I would modify Sea-orm-cli generate
to first read the pre-existing entities looking for specific comments used to mark sections to be preserved. These would be kept and after the new entity has been written these preserved sections would be inserted to replace the marked sections.
As a fail safe preserved code would be appended if the correct place can't be found (and written to a new file if the original entity file has disappeared (renamed table for example).
So for example standard entity currently ends with:
impl ActiveModelBehavior for ActiveModel {}
To preserve changes a customised version of this would be marked by specific comments like this
// ** modified from generated code start ** impl ActiveModelBehavior for ActiveModel {}
use chrono::Utc;
use sea_orm::{prelude::async_trait::async_trait, ActiveValue};
#[async_trait]
impl ActiveModelBehavior for ActiveModel {
async fn before_save<C: ConnectionTrait>(
mut self,
_db: &C,
insert: bool,
) -> Result<Self, DbErr> {
if insert {
self.id = ActiveValue::NotSet;
self.created_timestamp = ActiveValue::Set(Utc::now().to_string());
};
self.updated_timestamp = ActiveValue::Set(Utc::now().to_string());
Ok(self)
}
}
#[derive(DeriveIntoActiveModel, Serialize, Deserialize)]
pub struct BasicSong {
pub id: i32,
pub collection_id: i32,
pub number: i32,
pub title: String,
}
// ** modified from generated code end ** impl ActiveModelBehavior for ActiveModel {}
I am thinking that if the code after the start and end comment markers is the same then we are replacing a single line. If they differ then we start inserting our preserved code at the first and the look for the first occurrence of the end code.
eg to replace a single line with a section of code to be preserved
// ** modified from generated code start ** impl ActiveModelBehavior for ActiveModel {}
...
...
...
// ** modified from generated code end ** impl ActiveModelBehavior for ActiveModel {}
To replace multiple lines then this:
// ** modified from generated code start ** pub enum Relation {
my version of pub enum Relation {
...
...
my end }
// ** modified from generated code start ** }
Given my current rust experience I am thinking of a brute force approach.
- Scan all entity source files, collect all the sections to be preserved.
- Let generation happen as now
- Go back through the entities and add back the preserved text. If the right place can't be found (maybe the entity generation has been upgraded) then add the preserved text after a comment at the end of the entity file.
- If any entity sources with preserved text have disappeared (maybe the table has been renamed) then write the preserved text to the original source filename with a comment
If this isn't wanted in the sea-orm codebase then I can always write it as stand alone utilities (entity-store-preserved-code and entity-restore-preserved-code).