feat: simplify listing databases
This commit is contained in:
parent
6d4200d1e7
commit
a6bd54f447
|
|
@ -3,7 +3,7 @@ use crate::{blocking_brotli_compress, brotli_compress, Client};
|
||||||
use app_error::AppError;
|
use app_error::AppError;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use client_api_entity::workspace_dto::{
|
use client_api_entity::workspace_dto::{
|
||||||
AFDatabase, AFDatabaseRow, AFDatabaseRowDetail, ListDatabaseParam, ListDatabaseRowDetailParam,
|
AFDatabase, AFDatabaseRow, AFDatabaseRowDetail, ListDatabaseRowDetailParam,
|
||||||
};
|
};
|
||||||
use client_api_entity::{
|
use client_api_entity::{
|
||||||
BatchQueryCollabParams, BatchQueryCollabResult, CollabParams, CreateCollabParams,
|
BatchQueryCollabParams, BatchQueryCollabResult, CollabParams, CreateCollabParams,
|
||||||
|
|
@ -161,13 +161,11 @@ impl Client {
|
||||||
pub async fn list_databases(
|
pub async fn list_databases(
|
||||||
&self,
|
&self,
|
||||||
workspace_id: &str,
|
workspace_id: &str,
|
||||||
name_filter: Option<String>,
|
|
||||||
) -> Result<Vec<AFDatabase>, AppResponseError> {
|
) -> Result<Vec<AFDatabase>, AppResponseError> {
|
||||||
let url = format!("{}/api/workspace/{}/database", self.base_url, workspace_id);
|
let url = format!("{}/api/workspace/{}/database", self.base_url, workspace_id);
|
||||||
let resp = self
|
let resp = self
|
||||||
.http_client_with_auth(Method::GET, &url)
|
.http_client_with_auth(Method::GET, &url)
|
||||||
.await?
|
.await?
|
||||||
.query(&ListDatabaseParam { name_filter })
|
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
log_request_id(&resp);
|
log_request_id(&resp);
|
||||||
|
|
|
||||||
|
|
@ -293,11 +293,6 @@ pub struct QueryWorkspaceParam {
|
||||||
pub include_role: Option<bool>,
|
pub include_role: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Deserialize, Serialize)]
|
|
||||||
pub struct ListDatabaseParam {
|
|
||||||
pub name_filter: Option<String>, // logic: if database name contains
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Deserialize, Serialize)]
|
#[derive(Default, Debug, Deserialize, Serialize)]
|
||||||
pub struct ListDatabaseRowDetailParam {
|
pub struct ListDatabaseRowDetailParam {
|
||||||
// Comma separated database row ids
|
// Comma separated database row ids
|
||||||
|
|
@ -336,7 +331,6 @@ pub struct PublishedView {
|
||||||
pub struct AFDatabase {
|
pub struct AFDatabase {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub names: Vec<String>,
|
pub names: Vec<String>,
|
||||||
pub fields: Vec<AFDatabaseField>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
|
|
||||||
|
|
@ -1866,9 +1866,7 @@ async fn list_database_handler(
|
||||||
user_uuid: UserUuid,
|
user_uuid: UserUuid,
|
||||||
workspace_id: web::Path<String>,
|
workspace_id: web::Path<String>,
|
||||||
state: Data<AppState>,
|
state: Data<AppState>,
|
||||||
query: web::Query<ListDatabaseParam>,
|
|
||||||
) -> Result<Json<AppResponse<Vec<AFDatabase>>>> {
|
) -> Result<Json<AppResponse<Vec<AFDatabase>>>> {
|
||||||
let name_filter = query.into_inner().name_filter;
|
|
||||||
let uid = state.user_cache.get_user_uid(&user_uuid).await?;
|
let uid = state.user_cache.get_user_uid(&user_uuid).await?;
|
||||||
let workspace_id = workspace_id.into_inner();
|
let workspace_id = workspace_id.into_inner();
|
||||||
let dbs = biz::collab::ops::list_database(
|
let dbs = biz::collab::ops::list_database(
|
||||||
|
|
@ -1876,7 +1874,6 @@ async fn list_database_handler(
|
||||||
&state.collab_access_control_storage,
|
&state.collab_access_control_storage,
|
||||||
uid,
|
uid,
|
||||||
workspace_id,
|
workspace_id,
|
||||||
name_filter,
|
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
Ok(Json(AppResponse::Ok().with_data(dbs)))
|
Ok(Json(AppResponse::Ok().with_data(dbs)))
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ use database::publish::select_workspace_id_for_publish_namespace;
|
||||||
use database_entity::dto::QueryCollabResult;
|
use database_entity::dto::QueryCollabResult;
|
||||||
use database_entity::dto::{QueryCollab, QueryCollabParams};
|
use database_entity::dto::{QueryCollab, QueryCollabParams};
|
||||||
use shared_entity::dto::workspace_dto::AFDatabase;
|
use shared_entity::dto::workspace_dto::AFDatabase;
|
||||||
use shared_entity::dto::workspace_dto::AFDatabaseField;
|
|
||||||
use shared_entity::dto::workspace_dto::AFDatabaseRow;
|
use shared_entity::dto::workspace_dto::AFDatabaseRow;
|
||||||
use shared_entity::dto::workspace_dto::AFDatabaseRowDetail;
|
use shared_entity::dto::workspace_dto::AFDatabaseRowDetail;
|
||||||
use shared_entity::dto::workspace_dto::FavoriteFolderView;
|
use shared_entity::dto::workspace_dto::FavoriteFolderView;
|
||||||
|
|
@ -386,7 +385,6 @@ pub async fn list_database(
|
||||||
collab_storage: &CollabAccessControlStorage,
|
collab_storage: &CollabAccessControlStorage,
|
||||||
uid: i64,
|
uid: i64,
|
||||||
workspace_uuid_str: String,
|
workspace_uuid_str: String,
|
||||||
name_filter: Option<String>,
|
|
||||||
) -> Result<Vec<AFDatabase>, AppError> {
|
) -> Result<Vec<AFDatabase>, AppError> {
|
||||||
let workspace_uuid: Uuid = workspace_uuid_str.as_str().parse()?;
|
let workspace_uuid: Uuid = workspace_uuid_str.as_str().parse()?;
|
||||||
let ws_db_oid = select_workspace_database_oid(pg_pool, &workspace_uuid).await?;
|
let ws_db_oid = select_workspace_database_oid(pg_pool, &workspace_uuid).await?;
|
||||||
|
|
@ -407,72 +405,28 @@ pub async fn list_database(
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
let db_metas = ws_body.get_all_meta(&ws_body_collab.transact());
|
let db_metas = ws_body.get_all_meta(&ws_body_collab.transact());
|
||||||
let query_collabs: Vec<QueryCollab> = db_metas
|
|
||||||
.into_iter()
|
|
||||||
.map(|meta| QueryCollab {
|
|
||||||
object_id: meta.database_id.clone(),
|
|
||||||
collab_type: CollabType::Database,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let results = collab_storage
|
|
||||||
.batch_get_collab(&uid, query_collabs, true)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let txn = ws_body_collab.transact();
|
let folder = get_latest_collab_folder(
|
||||||
let mut af_databases: Vec<AFDatabase> = Vec::with_capacity(results.len());
|
collab_storage,
|
||||||
for (oid, result) in results {
|
GetCollabOrigin::User { uid },
|
||||||
match result {
|
&workspace_uuid_str,
|
||||||
QueryCollabResult::Success { encode_collab_v1 } => {
|
)
|
||||||
match EncodedCollab::decode_from_bytes(&encode_collab_v1) {
|
.await?;
|
||||||
Ok(ec) => {
|
|
||||||
match Collab::new_with_source(CollabOrigin::Server, &oid, ec.into(), vec![], false) {
|
|
||||||
Ok(db_collab) => match DatabaseBody::from_collab(
|
|
||||||
&db_collab,
|
|
||||||
Arc::new(NoPersistenceDatabaseCollabService),
|
|
||||||
None,
|
|
||||||
) {
|
|
||||||
Some(db_body) => {
|
|
||||||
let db_views = db_body.views.get_all_views_meta(&txn);
|
|
||||||
let names = db_views
|
|
||||||
.iter()
|
|
||||||
.map(|v| v.name.clone())
|
|
||||||
.filter(|name| !name.is_empty())
|
|
||||||
.collect::<Vec<String>>();
|
|
||||||
|
|
||||||
// if there exists a name filter,
|
let mut af_databases = Vec::with_capacity(db_metas.len());
|
||||||
// there must be at least one view name that contains the filter
|
for db_meta in db_metas {
|
||||||
if let Some(name_filter) = &name_filter {
|
let id = db_meta.database_id;
|
||||||
if !names.iter().any(|name| name.contains(name_filter)) {
|
let names: Vec<String> = db_meta
|
||||||
continue;
|
.linked_views
|
||||||
}
|
.into_iter()
|
||||||
}
|
.map(|view_id| {
|
||||||
|
folder
|
||||||
let db_fields = db_body.fields.get_all_fields(&txn);
|
.get_view(&view_id)
|
||||||
let mut af_fields: Vec<AFDatabaseField> = Vec::with_capacity(db_fields.len());
|
.map(|v| v.name.clone())
|
||||||
for db_field in db_fields {
|
.unwrap_or_default()
|
||||||
af_fields.push(AFDatabaseField {
|
})
|
||||||
name: db_field.name,
|
.collect();
|
||||||
field_type: format!("{:?}", FieldType::from(db_field.field_type)),
|
af_databases.push(AFDatabase { id, names });
|
||||||
});
|
|
||||||
}
|
|
||||||
af_databases.push(AFDatabase {
|
|
||||||
id: db_body.get_database_id(&txn),
|
|
||||||
names,
|
|
||||||
fields: af_fields,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
None => tracing::error!("Failed to create db_body from db_collab, oid: {}", oid),
|
|
||||||
},
|
|
||||||
Err(err) => tracing::error!("Failed to create db_collab: {:?}", err),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(err) => tracing::error!("Failed to decode collab: {:?}", err),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
QueryCollabResult::Failed { error } => {
|
|
||||||
tracing::warn!("Failed to get collab: {:?}", error)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(af_databases)
|
Ok(af_databases)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
use client_api_test::generate_unique_registered_user_client;
|
use client_api_test::generate_unique_registered_user_client;
|
||||||
use collab_entity::CollabType;
|
use collab_entity::CollabType;
|
||||||
use database_entity::dto::QueryCollabParams;
|
use database_entity::dto::QueryCollabParams;
|
||||||
use shared_entity::dto::workspace_dto::AFDatabaseField;
|
|
||||||
use shared_entity::dto::workspace_dto::CreateWorkspaceParam;
|
use shared_entity::dto::workspace_dto::CreateWorkspaceParam;
|
||||||
use shared_entity::dto::workspace_dto::PatchWorkspaceParam;
|
use shared_entity::dto::workspace_dto::PatchWorkspaceParam;
|
||||||
|
|
||||||
|
|
@ -13,54 +12,22 @@ async fn workspace_list_database() {
|
||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
{
|
{
|
||||||
let dbs = c.list_databases(&workspace_id, None).await.unwrap();
|
let dbs = c.list_databases(&workspace_id).await.unwrap();
|
||||||
assert_eq!(dbs.len(), 1);
|
assert_eq!(dbs.len(), 1, "{:?}", dbs);
|
||||||
|
let todos_db = &dbs[0];
|
||||||
let db = &dbs[0];
|
assert_eq!(todos_db.names.len(), 1);
|
||||||
|
assert!(todos_db.names.contains(&String::from("To-dos")));
|
||||||
assert_eq!(db.names.len(), 2);
|
|
||||||
assert!(db.names.contains(&String::from("Untitled")));
|
|
||||||
assert!(db.names.contains(&String::from("Grid")));
|
|
||||||
|
|
||||||
assert!(db.fields.contains(&AFDatabaseField {
|
|
||||||
name: "Last modified".to_string(),
|
|
||||||
field_type: "LastEditedTime".to_string(),
|
|
||||||
}));
|
|
||||||
assert!(db.fields.contains(&AFDatabaseField {
|
|
||||||
name: "Multiselect".to_string(),
|
|
||||||
field_type: "MultiSelect".to_string(),
|
|
||||||
}));
|
|
||||||
assert!(db.fields.contains(&AFDatabaseField {
|
|
||||||
name: "Tasks".to_string(),
|
|
||||||
field_type: "Checklist".to_string(),
|
|
||||||
}));
|
|
||||||
assert!(db.fields.contains(&AFDatabaseField {
|
|
||||||
name: "Status".to_string(),
|
|
||||||
field_type: "SingleSelect".to_string(),
|
|
||||||
}));
|
|
||||||
assert!(db.fields.contains(&AFDatabaseField {
|
|
||||||
name: "Description".to_string(),
|
|
||||||
field_type: "RichText".to_string(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let dbs = c
|
|
||||||
.list_databases(&workspace_id, Some(String::from("nomatch")))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(dbs.len(), 0);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let dbs = c
|
|
||||||
.list_databases(&workspace_id, Some(String::from("ntitle")))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(dbs.len(), 1);
|
|
||||||
{
|
{
|
||||||
let untitled_db = &dbs[0];
|
|
||||||
let db_row_ids = c
|
let db_row_ids = c
|
||||||
.list_database_row_ids(&workspace_id, &untitled_db.id)
|
.list_database_row_ids(&workspace_id, &todos_db.id)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(db_row_ids.len(), 5, "{:?}", db_row_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let db_row_ids = c
|
||||||
|
.list_database_row_ids(&workspace_id, &todos_db.id)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(db_row_ids.len(), 5, "{:?}", db_row_ids);
|
assert_eq!(db_row_ids.len(), 5, "{:?}", db_row_ids);
|
||||||
|
|
@ -68,7 +35,7 @@ async fn workspace_list_database() {
|
||||||
let db_row_ids: Vec<&str> = db_row_ids.iter().map(|s| s.id.as_str()).collect();
|
let db_row_ids: Vec<&str> = db_row_ids.iter().map(|s| s.id.as_str()).collect();
|
||||||
let db_row_ids: &[&str] = &db_row_ids;
|
let db_row_ids: &[&str] = &db_row_ids;
|
||||||
let db_row_details = c
|
let db_row_details = c
|
||||||
.list_database_row_details(&workspace_id, &untitled_db.id, db_row_ids)
|
.list_database_row_details(&workspace_id, &todos_db.id, db_row_ids)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(db_row_details.len(), 5, "{:#?}", db_row_details);
|
assert_eq!(db_row_details.len(), 5, "{:#?}", db_row_details);
|
||||||
|
|
@ -111,21 +78,6 @@ async fn workspace_list_database() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
|
||||||
let dbs = c
|
|
||||||
.list_databases(&workspace_id, Some(String::from("rid")))
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(dbs.len(), 1);
|
|
||||||
{
|
|
||||||
let grid_db = &dbs[0];
|
|
||||||
let db_row_ids = c
|
|
||||||
.list_database_row_ids(&workspace_id, &grid_db.id)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(db_row_ids.len(), 5, "{:?}", db_row_ids);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue