-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
editoast: remove InternalError usage in Delete and Create Model API #10196
base: dev
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. Additional details and impacted files@@ Coverage Diff @@
## dev #10196 +/- ##
==========================================
+ Coverage 79.94% 81.51% +1.56%
==========================================
Files 1057 1060 +3
Lines 106302 104448 -1854
Branches 724 722 -2
==========================================
+ Hits 84982 85138 +156
+ Misses 21278 19269 -2009
+ Partials 42 41 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
d790ad7
to
f75fab0
Compare
Signed-off-by: Leo Valais <leo.valais97@gmail.com>
Signed-off-by: Leo Valais <leo.valais97@gmail.com>
Signed-off-by: Leo Valais <leo.valais97@gmail.com>
Signed-off-by: Leo Valais <leo.valais97@gmail.com>
…els::Error Signed-off-by: Leo Valais <leo.valais97@gmail.com>
f75fab0
to
f4c7501
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job. Not approving yet, let's see where the comments goes first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about defining this directly in src/model.rs
? To me, defining the error is also about locality, meaning, where it will be used. I'm not a fan of defining error in its own module for that reason. On top of that:
src/model.rs
is empty so it won't clutter much (we can think later if it's start to not be the case)- you will avoid a
EditoastModelErrorError
in OpenAPI I believe and transform it intoEditoastModelError
😃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: this is the only instruction that defines what's being included in the OpenAPI. The module path is only used by derive(EditoastError)
to fill in fn get_type
.
inventory::submit! {
ErrorDefinition::new("editoast:model:ModelError", "Error", "ModelError", 500u16, r#"{}"#)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, so the commit does solve the complicate naming in OpenAPI. But yet, do we need a dedicated Rust module for the error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
/// Just like [Delete::delete] but returns `Err(fail())` if the row didn't exist | ||
async fn delete_or_fail<E, F>(&self, conn: &mut DbConnection, fail: F) -> Result<()> | ||
async fn delete_or_fail<E, F>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason why delete_or_fail()
is generic over the error E
but not delete()
above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point of delete
is to delete the row if it's there (hence the Ok(bool)
). The "fail" or delete_or_fail
represents the case where we expect the row to be there. In case it's not, it's a caller error that needs to be raised, not a model::Error
:
match self.delete(conn).await {
Ok(true) => Ok(()),
Ok(false) => Err(fail()), // fail(): E
Err(e) => Err(E::from(e)), // E: From<model::Error>
}
But PostgreSQL errors can still happen, so we need E
to "accept" model::Error
as well.
editoast/src/models/timetable.rs
Outdated
async fn delete_static( | ||
conn: &mut DbConnection, | ||
id: i64, | ||
) -> std::result::Result<bool, editoast_models::model::Error> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every place you change Result<something>
to std::result::Result<something, editoast_models::model::Error>
, you can do this instead Result<something, editoast_models::model::Error>
because our crate::error::Result
is generic over the error with a default value (so you can just override it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha, well, you changed this only place, but there was a lot of places in your PR where you can do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I thought your comment was about this one specifically since the traits are implemented manually for timetables. I'll change the occurrences in the trait functions but for the quoted code in the macros I'd prefer to keep the fully qualified path:
- macro hygiene
- it lifts ambiguity since "jump to definition" isn't available in snapshots or quoted code
crate::error::Result
will disappear after theViewError
migration, so that's one less thing we'll have to do in the future
Wdyt?
) { | ||
TemporarySpeedLimitError::NameAlreadyUsed { | ||
name: name.as_ref().to_string(), | ||
impl From<model::Error> for TemporarySpeedLimitError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will we have to write all From
manually from now on? Or is it just a temporary situation until we finish the migration to the new error model (I feel I'm missing a part of the big picture here). If it's the former, then we might to discuss it because I'm not sure we would want that everywhere, what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only when we can't write:
#[error(transparent)]
#[editoast_error(status = 500)]
Database(#[from] model::Error),
because we want the from
operation to perform some decisions about which variant to return, like here. When it's just a forwarding, thiserror
generates this implementation.
@@ -158,7 +172,7 @@ async fn create_temporary_speed_limit_group( | |||
.creation_date(Utc::now().naive_utc()) | |||
.create(conn) | |||
.await | |||
.map_err(|e| map_diesel_error(e, speed_limit_group_name))?; | |||
.map_err(|e| TemporarySpeedLimitError::from(e).with_name(speed_limit_group_name))?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe implementing From
is not adapted here. We might need a real new()
constructor? What do you think? Or else, we might think about UniqueViolation
containing the value of the conflicting key?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for making me look again the information provided by the error. I believe we can parse the conflicting key and add it to the error.
There may be a way to interface the error with trait Identifiable<K>
and trait PreferredIdentifier<K>
. I'll look into it.
But before that can we resolve #10196 (comment) (conflicts...)
pub trait DatabaseErrorInformation {
/// The primary human-readable error message. Typically one line.
fn message(&self) -> &str;
/// An optional secondary error message providing more details about the
/// problem, if it was provided by the database. Might span multiple lines.
fn details(&self) -> Option<&str>;
/// An optional suggestion of what to do about the problem, if one was
/// provided by the database.
fn hint(&self) -> Option<&str>;
/// The name of the table the error was associated with, if the error was
/// associated with a specific table and the backend supports retrieving
/// that information.
///
/// Currently this method will return `None` for all backends other than
/// PostgreSQL.
fn table_name(&self) -> Option<&str>;
/// The name of the column the error was associated with, if the error was
/// associated with a specific column and the backend supports retrieving
/// that information.
///
/// Currently this method will return `None` for all backends other than
/// PostgreSQL.
fn column_name(&self) -> Option<&str>;
/// The constraint that was violated if this error is a constraint violation
/// and the backend supports retrieving that information.
///
/// Currently this method will return `None` for all backends other than
/// PostgreSQL.
fn constraint_name(&self) -> Option<&str>;
/// An optional integer indicating an error cursor position as an index into
/// the original statement string.
fn statement_position(&self) -> Option<i32>;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a proposition: 6257f64
I like it better this way, but I wish we didn't have to bother knowing table columns and constraints using models in views. Table definitions are "implementation details" from the views point of view. But that's out of scope of this PR (maybe ModelV3? :p)
editoast/src/views/rolling_stock.rs
Outdated
} | ||
|
||
impl RollingStockError { | ||
fn with_name(self, name: String) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might be able to avoid this weird function/pattern if model::Error::UniqueViolation
is able to retain the key that created the conflict.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use regex::Regex; | ||
|
||
#[derive(Debug, thiserror::Error)] | ||
pub enum Error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we would need a CreateError
and a DeleteError
? From what I understand, they semantically can produce different set of error variants... but diesel
seems to have made the choice to only have one enum
for them all (even if different functions may only return a subset of it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that I understand how is this related to #10196 (comment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't, sorry 😅
I asked myself the same question. I don't think there will be much difference between each trait's error type. Retrieve
may have less error cases, but I don't think that'd be worth dealing with 5+ error types for the Model
API alone. I could be proved wrong after having migrated the rest of the traits, but at least for Create
and Delete
, I believe that holds. Wait and see, or do we split them now and merge them if that's deemed unnecessary later?
Signed-off-by: Leo Valais <leo.valais97@gmail.com>
Signed-off-by: Leo Valais <leo.valais97@gmail.com>
…ls::Error Signed-off-by: Leo Valais <leo.valais97@gmail.com>
Signed-off-by: Leo Valais <leo.valais97@gmail.com>
1ed77d0
to
a15b78c
Compare
Signed-off-by: Leo Valais <leo.valais97@gmail.com>
diesel::result::Error
ineditoast_models
views
(mostly)map_diesel_error
here and thereeditoast_models::model
laterTip
Review commit by commit