Custom types in model fields to improve type safety #1310
Replies: 2 comments 6 replies
-
Hey @AngelOnFira, thanks for the sharing. Interesting use of the type system! I guess we can start by providing a easier interface to use custom type (newtype) in SeaORM model. pub struct DatabaseId(pub i32);
impl From<DatabaseId> for Value {
fn from(source: StringVec) -> Self { ... }
}
impl TryGetable for DatabaseId {
fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result<Self, TryGetError> { ... }
}
impl sea_query::ValueType for StringVec { ... } A derive macro can implement all these traits on behalf of the user. |
Beta Was this translation helpful? Give feedback.
-
I had another thought on this topic so I thought I'd add it in here. For some entity: // ...
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "challenge")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
// ...
}
// ... It could be quite helpful to get codegen to generate a custom type for the primary key. It could be an opt-in flag when generating entities. for example, it might instead generate this: // ...
pub type ChallengeTablePK = i32; // <--
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "challenge")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: ChallengeTablePK, // <--
// ...
}
// ... This way, when I'm passing this table's primary key around, it could easy to have a type that just comes with the entity that I could use. I came up with this when I was thinking of creating another file in my entities crate to do this manually. Thoughts @billy1624 @tyt2y3? |
Beta Was this translation helpful? Give feedback.
-
I'm just brainstorming a bit, but one type safety thing I've come across and feel that I'm missing is taking data from the database that could represent multiple things. Take this entity model for example:
In this model, I'm storing a few things:
discord_id
that I would get from this object (say a channel)guild_id
, which isn't actually the id of a Discord Guild (server), but instead the id of a row in another table in some relationshipchannel_id
, which is also a pointer to somewhere else in the database.I've done some type mangling for the sake of this argument (since Discord actually stores IDs in an
i64
sized variable), but I think this pattern might extend past my example.So in this case, when I get this model from the database, it's up to me as the developer to remember which of those are Discord IDs, and which are IDs of Database rows. I suppose there could be some ways to improve this:
So both of those options don't really force the end user to do something in a certain way.
What I'm trying in my codebase right now is using two separate structs to track what kind of ID it is:
And what I feel I want to do is something along the lines of:
So that when I get the model from the database, although they both hold the same type internally, they can't be passed off to the wrong functions right away. These types would only hold a primitive datatype that could map to a normal field type, and are really just acting as markers.
Anyways, I was just thinking about this a bit and wanted to put it in words. I was just reading #1309 and might try making some abstraction in my
entity
crate to see if I can enforce anything. It could also be that I'm approaching this from a naive perspective, and there is in fact a much better way to think about the problem.I'll try to update as I play around more!
Beta Was this translation helpful? Give feedback.
All reactions