-
Notifications
You must be signed in to change notification settings - Fork 321
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4871 from systeminit/victor/eng-2803-implement-th…
…e-views-cru feat: Create update and list endpoints for views
- Loading branch information
Showing
7 changed files
with
311 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
use crate::app_state::AppState; | ||
use crate::service::ApiError; | ||
use axum::http::StatusCode; | ||
use axum::response::{IntoResponse, Response}; | ||
use axum::routing::{get, post, put}; | ||
use axum::Router; | ||
use dal::diagram::view::{View, ViewId}; | ||
use dal::{ChangeSetError, DalContext, Timestamp, TransactionsError}; | ||
use serde::{Deserialize, Serialize}; | ||
use thiserror::Error; | ||
|
||
pub mod create_view; | ||
pub mod list_views; | ||
pub mod update_view; | ||
|
||
#[remain::sorted] | ||
#[derive(Debug, Error)] | ||
pub enum ViewError { | ||
#[error("changeset error: {0}")] | ||
ChangeSet(#[from] ChangeSetError), | ||
#[error("dal diagram error: {0}")] | ||
DalDiagram(#[from] dal::diagram::DiagramError), | ||
#[error("there is already a view called {0}")] | ||
NameAlreadyInUse(String), | ||
#[error("transactions error: {0}")] | ||
Transactions(#[from] TransactionsError), | ||
} | ||
|
||
pub type ViewResult<T> = Result<T, ViewError>; | ||
|
||
impl IntoResponse for ViewError { | ||
fn into_response(self) -> Response { | ||
let (status_code, error_message) = match self { | ||
ViewError::NameAlreadyInUse(_) => (StatusCode::UNPROCESSABLE_ENTITY, self.to_string()), | ||
|
||
_ => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()), | ||
}; | ||
|
||
ApiError::new(status_code, error_message).into_response() | ||
} | ||
} | ||
|
||
/// Frontend representation for a [View](View). | ||
/// Yeah, it's a silly name, but all the other frontend representation structs are *View, | ||
/// so we either keep it or change everything. | ||
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)] | ||
pub struct ViewView { | ||
id: ViewId, | ||
name: String, | ||
is_default: bool, | ||
#[serde(flatten)] | ||
timestamp: Timestamp, | ||
} | ||
|
||
impl ViewView { | ||
pub async fn from_view(ctx: &DalContext, view: View) -> ViewResult<Self> { | ||
Ok(ViewView { | ||
id: view.id(), | ||
name: view.name().to_owned(), | ||
is_default: view.is_default(ctx).await?, | ||
timestamp: view.timestamp().to_owned(), | ||
}) | ||
} | ||
} | ||
|
||
pub fn v2_routes() -> Router<AppState> { | ||
Router::new() | ||
// Func Stuff | ||
.route("/", get(list_views::list_views)) | ||
.route("/", post(create_view::create_view)) | ||
.route("/:view_id", put(update_view::update_view)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
use crate::extract::{AccessBuilder, HandlerContext, PosthogClient}; | ||
use crate::service::force_change_set_response::ForceChangeSetResponse; | ||
use crate::service::v2::view::{ViewError, ViewResult, ViewView}; | ||
use crate::tracking::track; | ||
use axum::extract::{Host, OriginalUri, Path}; | ||
use axum::Json; | ||
use dal::diagram::view::View; | ||
use dal::{ChangeSet, ChangeSetId, WorkspacePk}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Deserialize, Serialize, Debug)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Request { | ||
pub name: String, | ||
} | ||
|
||
pub async fn create_view( | ||
HandlerContext(builder): HandlerContext, | ||
AccessBuilder(access_builder): AccessBuilder, | ||
PosthogClient(posthog_client): PosthogClient, | ||
OriginalUri(original_uri): OriginalUri, | ||
Host(host_name): Host, | ||
Path((_workspace_pk, change_set_id)): Path<(WorkspacePk, ChangeSetId)>, | ||
Json(Request { name }): Json<Request>, | ||
) -> ViewResult<ForceChangeSetResponse<ViewView>> { | ||
let mut ctx = builder | ||
.build(access_builder.build(change_set_id.into())) | ||
.await?; | ||
|
||
if View::find_by_name(&ctx, name.as_str()).await?.is_some() { | ||
return Err(ViewError::NameAlreadyInUse(name)); | ||
} | ||
|
||
let force_change_set_id = ChangeSet::force_new(&mut ctx).await?; | ||
|
||
let view = View::new(&ctx, name).await?; | ||
|
||
track( | ||
&posthog_client, | ||
&ctx, | ||
&original_uri, | ||
&host_name, | ||
"create_view", | ||
serde_json::json!({ | ||
"how": "/diagram/create_view", | ||
"view_id": view.id(), | ||
"view_name": view.name(), | ||
"change_set_id": ctx.change_set_id(), | ||
}), | ||
); | ||
|
||
ctx.commit().await?; | ||
|
||
Ok(ForceChangeSetResponse::new( | ||
force_change_set_id, | ||
ViewView::from_view(&ctx, view).await?, | ||
)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
use crate::extract::{AccessBuilder, HandlerContext}; | ||
use crate::service::v2::view::{ViewResult, ViewView}; | ||
use axum::extract::{Json, Path}; | ||
use dal::diagram::view::View; | ||
use dal::{ChangeSetId, Visibility, WorkspacePk}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Deserialize, Serialize, Debug)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Request { | ||
#[serde(flatten)] | ||
pub visibility: Visibility, | ||
} | ||
|
||
pub type Response = Vec<ViewView>; | ||
|
||
pub async fn list_views( | ||
HandlerContext(builder): HandlerContext, | ||
AccessBuilder(access_builder): AccessBuilder, | ||
Path((_workspace_pk, change_set_id)): Path<(WorkspacePk, ChangeSetId)>, | ||
) -> ViewResult<Json<Response>> { | ||
let ctx = builder | ||
.build(access_builder.build(change_set_id.into())) | ||
.await?; | ||
|
||
let mut views = vec![]; | ||
for view in View::list(&ctx).await? { | ||
views.push(ViewView::from_view(&ctx, view).await?); | ||
} | ||
|
||
Ok(Json(views)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
use crate::extract::{AccessBuilder, HandlerContext, PosthogClient}; | ||
use crate::service::force_change_set_response::ForceChangeSetResponse; | ||
use crate::service::v2::view::{ViewError, ViewResult}; | ||
use crate::tracking::track; | ||
use axum::extract::{Host, OriginalUri, Path}; | ||
use axum::Json; | ||
use dal::diagram::view::{View, ViewId}; | ||
use dal::{ChangeSet, ChangeSetId, WorkspacePk}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Deserialize, Serialize, Debug)] | ||
#[serde(rename_all = "camelCase")] | ||
pub struct Request { | ||
pub name: String, | ||
} | ||
|
||
pub async fn update_view( | ||
HandlerContext(builder): HandlerContext, | ||
AccessBuilder(access_builder): AccessBuilder, | ||
PosthogClient(posthog_client): PosthogClient, | ||
OriginalUri(original_uri): OriginalUri, | ||
Host(host_name): Host, | ||
Path((_workspace_pk, change_set_id, view_id)): Path<(WorkspacePk, ChangeSetId, ViewId)>, | ||
Json(Request { name }): Json<Request>, | ||
) -> ViewResult<ForceChangeSetResponse<()>> { | ||
let mut ctx = builder | ||
.build(access_builder.build(change_set_id.into())) | ||
.await?; | ||
|
||
// NOTE(victor) We want to still move the user to a new changeset if they ran an update event, | ||
// just don't change any data if they tried to rename the changeset to the name it already has | ||
let should_update = if let Some(view) = View::find_by_name(&ctx, name.as_str()).await? { | ||
if view.id() == view_id { | ||
false | ||
} else { | ||
return Err(ViewError::NameAlreadyInUse(name)); | ||
} | ||
} else { | ||
true | ||
}; | ||
|
||
let force_change_set_id = ChangeSet::force_new(&mut ctx).await?; | ||
|
||
if should_update { | ||
let mut view = View::get_by_id(&ctx, view_id).await?; | ||
let old_view_name = view.name().to_owned(); | ||
view.set_name(&ctx, name).await?; | ||
|
||
track( | ||
&posthog_client, | ||
&ctx, | ||
&original_uri, | ||
&host_name, | ||
"update_view", | ||
serde_json::json!({ | ||
"how": "/diagram/update_view", | ||
"view_id": view.id(), | ||
"view_new_name": view.name(), | ||
"view_old_name": old_view_name, | ||
"change_set_id": ctx.change_set_id(), | ||
}), | ||
); | ||
} | ||
|
||
ctx.commit().await?; | ||
|
||
Ok(ForceChangeSetResponse::new(force_change_set_id, ())) | ||
} |