fix(schema): handle view DDL object types
This commit is contained in:
parent
7643148708
commit
22b8ba17bb
|
|
@ -728,7 +728,7 @@ async function confirmBatchDropTables() {
|
|||
async function exportStructure(row: ObjectBrowserRow) {
|
||||
try {
|
||||
const schema = row.schema || selectedSchema.value || props.database;
|
||||
const ddl = await api.getTableDdl(props.connection.id, props.database, schema, row.name);
|
||||
const ddl = await api.getTableDdl(props.connection.id, props.database, schema, row.name, row.type === "VIEW" ? "VIEW" : undefined);
|
||||
await saveFileContent(ddl + "\n", `${row.name}.sql`, "SQL", "sql");
|
||||
} catch (e: any) {
|
||||
console.error("Export structure failed:", e);
|
||||
|
|
|
|||
|
|
@ -2096,7 +2096,7 @@ async function exportStructure() {
|
|||
const parts: string[] = [];
|
||||
for (const target of targets) {
|
||||
await connectionStore.ensureConnected(target.connectionId);
|
||||
const ddl = await api.getTableDdl(target.connectionId, target.database, target.schema || target.database, target.label);
|
||||
const ddl = await api.getTableDdl(target.connectionId, target.database, target.schema || target.database, target.label, target.type === "view" ? "VIEW" : undefined);
|
||||
parts.push(ddl.trim());
|
||||
}
|
||||
structurePreviewSql.value = `${parts.filter(Boolean).join("\n\n")}\n`;
|
||||
|
|
|
|||
|
|
@ -408,8 +408,8 @@ export async function listSchemas(connectionId: string, database: string): Promi
|
|||
return get(`/api/schema/schemas?${qs({ connection_id: connectionId, database })}`);
|
||||
}
|
||||
|
||||
export async function listTables(connectionId: string, database: string, schema: string, filter?: string, limit?: number, offset?: number): Promise<TableInfo[]> {
|
||||
return get(`/api/schema/tables?${qs({ connection_id: connectionId, database, schema, filter, limit, offset })}`);
|
||||
export async function listTables(connectionId: string, database: string, schema: string, filter?: string, limit?: number, offset?: number, objectTypes?: SidebarObjectKind[]): Promise<TableInfo[]> {
|
||||
return get(`/api/schema/tables?${qs({ connection_id: connectionId, database, schema, filter, limit, offset, object_types: objectTypes?.join(",") })}`);
|
||||
}
|
||||
|
||||
export async function listObjects(connectionId: string, database: string, schema: string, objectTypes?: SidebarObjectKind[]): Promise<ObjectInfo[]> {
|
||||
|
|
@ -447,8 +447,8 @@ export async function listTriggers(connectionId: string, database: string, schem
|
|||
return get(`/api/schema/triggers?${qs({ connection_id: connectionId, database, schema, table })}`);
|
||||
}
|
||||
|
||||
export async function getTableDdl(connectionId: string, database: string, schema: string, table: string): Promise<string> {
|
||||
return get(`/api/schema/ddl?${qs({ connection_id: connectionId, database, schema, table })}`);
|
||||
export async function getTableDdl(connectionId: string, database: string, schema: string, table: string, objectType?: ObjectSourceKind): Promise<string> {
|
||||
return get(`/api/schema/ddl?${qs({ connection_id: connectionId, database, schema, table, object_type: objectType })}`);
|
||||
}
|
||||
|
||||
export async function prepareSchemaDiff(options: SchemaDiffPreparationOptions): Promise<SchemaDiffPreparation> {
|
||||
|
|
|
|||
|
|
@ -486,8 +486,8 @@ export async function deleteSchemaCachePrefix(prefix: string): Promise<void> {
|
|||
return invoke("delete_schema_cache_prefix", { prefix });
|
||||
}
|
||||
|
||||
export async function listTables(connectionId: string, database: string, schema: string, filter?: string, limit?: number, offset?: number): Promise<TableInfo[]> {
|
||||
return invoke("list_tables", { connectionId, database, schema, filter, limit, offset });
|
||||
export async function listTables(connectionId: string, database: string, schema: string, filter?: string, limit?: number, offset?: number, objectTypes?: SidebarObjectKind[]): Promise<TableInfo[]> {
|
||||
return invoke("list_tables", { connectionId, database, schema, filter, limit, offset, objectTypes });
|
||||
}
|
||||
|
||||
export async function listObjects(connectionId: string, database: string, schema: string, objectTypes?: SidebarObjectKind[]): Promise<ObjectInfo[]> {
|
||||
|
|
@ -787,8 +787,8 @@ export async function listTriggers(connectionId: string, database: string, schem
|
|||
return invoke("list_triggers", { connectionId, database, schema, table });
|
||||
}
|
||||
|
||||
export async function getTableDdl(connectionId: string, database: string, schema: string, table: string): Promise<string> {
|
||||
return invoke("get_table_ddl", { connectionId, database, schema, table });
|
||||
export async function getTableDdl(connectionId: string, database: string, schema: string, table: string, objectType?: ObjectSourceKind): Promise<string> {
|
||||
return invoke("get_table_ddl", { connectionId, database, schema, table, objectType });
|
||||
}
|
||||
|
||||
export async function prepareSchemaDiff(options: SchemaDiffPreparationOptions): Promise<SchemaDiffPreparation> {
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
|||
// When searching, fetch all matching tables (no pagination) — backend filter
|
||||
// already narrows the result set, so client-side filtering is not needed.
|
||||
const fetchLimit = searchFilter ? undefined : options.pageSize + 1;
|
||||
const tables = await api.listTables(options.node.connectionId, options.node.database, options.querySchema, searchFilter, fetchLimit, searchFilter ? undefined : options.offset);
|
||||
const tables = await api.listTables(options.node.connectionId, options.node.database, options.querySchema, searchFilter, fetchLimit, searchFilter ? undefined : options.offset, options.objectTypes);
|
||||
const hasMore = searchFilter ? false : tables.length > options.pageSize;
|
||||
const pageTables = hasMore ? tables.slice(0, options.pageSize) : tables;
|
||||
const objects = mergeTableInfosIntoObjects([], pageTables, options.effectiveSchema);
|
||||
|
|
|
|||
|
|
@ -370,6 +370,7 @@ async fn build_schema_prompt(agent_ctx: &AgentLoopContext, system_prompt: &str)
|
|||
None,
|
||||
Some(50), // smaller limit for prompt injection
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
|||
|
|
@ -241,6 +241,7 @@ async fn execute_list_tables(
|
|||
None,
|
||||
Some(LIST_TABLES_LIMIT + 1),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| format!("Failed to list tables: {e}"))?;
|
||||
|
|
|
|||
|
|
@ -2715,8 +2715,9 @@ mod tests {
|
|||
|
||||
let schemas = schema::list_schemas_core(&state, "kwdb-live", &database).await.unwrap();
|
||||
assert!(schemas.iter().any(|schema| schema == test_schema));
|
||||
let tables =
|
||||
schema::list_tables_core(&state, "kwdb-live", &database, test_schema, None, None, None).await.unwrap();
|
||||
let tables = schema::list_tables_core(&state, "kwdb-live", &database, test_schema, None, None, None, None)
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(tables.iter().any(|table| table.name == "devices" && table.table_type == "BASE TABLE"));
|
||||
let columns = schema::get_columns_core(&state, "kwdb-live", &database, test_schema, "devices").await.unwrap();
|
||||
let id_column = columns.iter().find(|column| column.name == "id").expect("id column should be listed");
|
||||
|
|
|
|||
|
|
@ -383,6 +383,7 @@ pub async fn export_database_sql_core(
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
let all_tables = filter_selected_table_infos(all_tables, &request.selected_tables);
|
||||
|
|
@ -476,6 +477,7 @@ pub async fn export_database_sql_core(
|
|||
&request.database,
|
||||
&request.schema,
|
||||
table_name,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
|
|
|||
|
|
@ -423,9 +423,10 @@ pub async fn list_tables_core(
|
|||
filter: Option<&str>,
|
||||
limit: Option<usize>,
|
||||
offset: Option<usize>,
|
||||
object_types: Option<&[String]>,
|
||||
) -> Result<Vec<db::TableInfo>, String> {
|
||||
retry_metadata_connection(state, connection_id, Some(database), || {
|
||||
list_tables_once(state, connection_id, database, schema, filter, limit, offset)
|
||||
list_tables_once(state, connection_id, database, schema, filter, limit, offset, object_types)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
|
@ -438,6 +439,7 @@ async fn list_tables_once(
|
|||
filter: Option<&str>,
|
||||
limit: Option<usize>,
|
||||
offset: Option<usize>,
|
||||
object_types: Option<&[String]>,
|
||||
) -> Result<Vec<db::TableInfo>, String> {
|
||||
let pool_key = state.get_or_create_pool(connection_id, Some(database)).await?;
|
||||
#[cfg(feature = "duckdb-bundled")]
|
||||
|
|
@ -456,7 +458,7 @@ async fn list_tables_once(
|
|||
})
|
||||
.await
|
||||
.map_err(|e| e.to_string())?
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset));
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types));
|
||||
}
|
||||
if let Some(PoolKind::ExternalDriver { config, session, .. }) = connections.get(&pool_key) {
|
||||
let config = config.clone();
|
||||
|
|
@ -468,26 +470,35 @@ async fn list_tables_once(
|
|||
serde_json::json!({ "connection": config.as_ref(), "database": database, "schema": schema }),
|
||||
)
|
||||
.await
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset));
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types));
|
||||
}
|
||||
#[cfg(feature = "duckdb-bundled")]
|
||||
if let Some(con) = extract_pool!(&connections, &pool_key, DuckDb) {
|
||||
drop(connections);
|
||||
let con = con.lock().map_err(|e| e.to_string())?;
|
||||
return duckdb_query_tables_in_database_with_attached(&con, database, schema, &duckdb_attached_names)
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset));
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types));
|
||||
}
|
||||
if let Some(client) = extract_pool!(&connections, &pool_key, ClickHouse) {
|
||||
drop(connections);
|
||||
return db::clickhouse_driver::list_tables(&client, clickhouse_metadata_database(database, schema))
|
||||
.await
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset));
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types));
|
||||
}
|
||||
if let Some(client) = extract_pool!(&connections, &pool_key, InfluxDb) {
|
||||
drop(connections);
|
||||
return db::influxdb_driver::list_tables(&client, database)
|
||||
.await
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset));
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types));
|
||||
}
|
||||
if object_types.is_some() {
|
||||
if let Some(client) = extract_pool!(&connections, &pool_key, SqlServer) {
|
||||
drop(connections);
|
||||
let mut client = client.lock().await;
|
||||
return db::sqlserver::list_tables(&mut client, schema, filter, None, None)
|
||||
.await
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types));
|
||||
}
|
||||
}
|
||||
try_sqlserver!(connections, &pool_key, list_tables, schema, filter, limit, offset);
|
||||
if let Some(client) = extract_pool!(&connections, &pool_key, Agent) {
|
||||
|
|
@ -495,14 +506,22 @@ async fn list_tables_once(
|
|||
drop(connections);
|
||||
let mut client = client.lock().await;
|
||||
match client.list_tables::<Vec<db::TableInfo>>(database, schema).await {
|
||||
Ok(tables) if !tables.is_empty() => return Ok(filter_table_infos(tables, filter, limit, offset)),
|
||||
Ok(tables) if !tables.is_empty() => {
|
||||
return Ok(filter_table_infos(tables, filter, limit, offset, object_types))
|
||||
}
|
||||
Ok(tables) => {
|
||||
if let Some(config) = fallback_config.as_ref() {
|
||||
match native_postgres_metadata_pool(state, connection_id, database, config).await {
|
||||
Ok(Some(pool)) => {
|
||||
return db::postgres::list_tables_filtered(&pool, schema, filter, limit, offset).await;
|
||||
return if object_types.is_some() {
|
||||
db::postgres::list_tables_filtered(&pool, schema, filter, None, None)
|
||||
.await
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types))
|
||||
} else {
|
||||
db::postgres::list_tables_filtered(&pool, schema, filter, limit, offset).await
|
||||
};
|
||||
}
|
||||
Ok(None) => return Ok(filter_table_infos(tables, filter, limit, offset)),
|
||||
Ok(None) => return Ok(filter_table_infos(tables, filter, limit, offset, object_types)),
|
||||
Err(error) => {
|
||||
log::warn!(
|
||||
"[schema][agent:list_tables:fallback-failed] connection_id={} database={} schema={} error={}",
|
||||
|
|
@ -514,20 +533,23 @@ async fn list_tables_once(
|
|||
}
|
||||
}
|
||||
}
|
||||
return Ok(filter_table_infos(tables, filter, limit, offset));
|
||||
return Ok(filter_table_infos(tables, filter, limit, offset, object_types));
|
||||
}
|
||||
Err(agent_error) => {
|
||||
if let Some(config) = fallback_config.as_ref() {
|
||||
if let Some(pool) =
|
||||
native_postgres_metadata_pool(state, connection_id, database, config).await?
|
||||
{
|
||||
return db::postgres::list_tables_filtered(&pool, schema, filter, limit, offset)
|
||||
.await
|
||||
.map_err(|fallback_error| {
|
||||
format!(
|
||||
"{agent_error}\n\nNative PostgreSQL metadata fallback failed: {fallback_error}"
|
||||
)
|
||||
});
|
||||
let result = if object_types.is_some() {
|
||||
db::postgres::list_tables_filtered(&pool, schema, filter, None, None)
|
||||
.await
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types))
|
||||
} else {
|
||||
db::postgres::list_tables_filtered(&pool, schema, filter, limit, offset).await
|
||||
};
|
||||
return result.map_err(|fallback_error| {
|
||||
format!("{agent_error}\n\nNative PostgreSQL metadata fallback failed: {fallback_error}")
|
||||
});
|
||||
}
|
||||
}
|
||||
return Err(agent_error);
|
||||
|
|
@ -543,30 +565,40 @@ async fn list_tables_once(
|
|||
PoolKind::Mysql(p, _) if db_config.as_ref().is_some_and(is_doris_family_config) => {
|
||||
db::mysql::list_tables_show(p, database)
|
||||
.await
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset))
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types))
|
||||
}
|
||||
PoolKind::Mysql(p, mode) => {
|
||||
dispatch_mysql!(p, mode, db::mysql::list_tables, db::ob_oracle::list_tables, schema)
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset))
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types))
|
||||
}
|
||||
PoolKind::Postgres(p) if db_config.as_ref().is_some_and(is_questdb_config) => {
|
||||
db::questdb::list_tables(p, schema).await.map(|tables| filter_table_infos(tables, filter, limit, offset))
|
||||
db::questdb::list_tables(p, schema)
|
||||
.await
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types))
|
||||
}
|
||||
PoolKind::Postgres(p) => db::postgres::list_tables_filtered(p, schema, filter, limit, offset).await,
|
||||
PoolKind::Sqlite(p) => {
|
||||
db::sqlite::list_tables(p, schema).await.map(|tables| filter_table_infos(tables, filter, limit, offset))
|
||||
PoolKind::Postgres(p) => {
|
||||
if object_types.is_some() {
|
||||
db::postgres::list_tables_filtered(p, schema, filter, None, None)
|
||||
.await
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types))
|
||||
} else {
|
||||
db::postgres::list_tables_filtered(p, schema, filter, limit, offset).await
|
||||
}
|
||||
}
|
||||
PoolKind::Sqlite(p) => db::sqlite::list_tables(p, schema)
|
||||
.await
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types)),
|
||||
PoolKind::Rqlite(client) => db::rqlite_driver::list_tables(client, schema)
|
||||
.await
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset)),
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types)),
|
||||
PoolKind::MongoDb(client) => db::mongo_driver::list_collections(client, database)
|
||||
.await
|
||||
.map(|names| collection_names_to_tables(names, "COLLECTION"))
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset)),
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types)),
|
||||
PoolKind::Elasticsearch(client) => db::elasticsearch_driver::list_indices(client)
|
||||
.await
|
||||
.map(|names| collection_names_to_tables(names, "INDEX"))
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset)),
|
||||
.map(|tables| filter_table_infos(tables, filter, limit, offset, object_types)),
|
||||
_ => Ok(vec![]),
|
||||
}
|
||||
}
|
||||
|
|
@ -589,6 +621,7 @@ fn filter_table_infos(
|
|||
filter: Option<&str>,
|
||||
limit: Option<usize>,
|
||||
offset: Option<usize>,
|
||||
object_types: Option<&[String]>,
|
||||
) -> Vec<db::TableInfo> {
|
||||
let filter = filter.unwrap_or("").to_lowercase();
|
||||
let limit = limit.unwrap_or(usize::MAX);
|
||||
|
|
@ -596,11 +629,40 @@ fn filter_table_infos(
|
|||
tables
|
||||
.into_iter()
|
||||
.filter(|table| filter.is_empty() || table.name.to_lowercase().contains(&filter))
|
||||
.filter(|table| table_info_matches_object_types(table, object_types))
|
||||
.skip(offset)
|
||||
.take(limit)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn table_info_matches_object_types(table: &db::TableInfo, object_types: Option<&[String]>) -> bool {
|
||||
let Some(object_types) = object_types else {
|
||||
return true;
|
||||
};
|
||||
if object_types.is_empty() {
|
||||
return true;
|
||||
}
|
||||
let table_type = normalize_table_info_object_type(&table.table_type);
|
||||
object_types.iter().any(|object_type| normalize_table_info_object_type(object_type) == table_type)
|
||||
}
|
||||
|
||||
fn normalize_table_info_object_type(value: &str) -> String {
|
||||
let upper = value.to_ascii_uppercase().replace(' ', "_");
|
||||
if upper.contains("MATERIALIZED") && upper.contains("VIEW") {
|
||||
return "MATERIALIZED_VIEW".to_string();
|
||||
}
|
||||
if upper.contains("VIEW") {
|
||||
return "VIEW".to_string();
|
||||
}
|
||||
if upper.contains("COLLECTION") {
|
||||
return "COLLECTION".to_string();
|
||||
}
|
||||
if upper.contains("INDEX") {
|
||||
return "INDEX".to_string();
|
||||
}
|
||||
"TABLE".to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
|
|
@ -738,12 +800,40 @@ mod tests {
|
|||
test_table_info("users"),
|
||||
];
|
||||
|
||||
let filtered = filter_table_infos(tables, Some("audit"), Some(1), Some(1));
|
||||
let filtered = filter_table_infos(tables, Some("audit"), Some(1), Some(1), None);
|
||||
|
||||
assert_eq!(filtered.len(), 1);
|
||||
assert_eq!(filtered[0].name, "audit_record");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filter_table_infos_filters_object_type_before_offset_and_limit() {
|
||||
let tables = vec![
|
||||
test_table_info("orders"),
|
||||
super::db::TableInfo {
|
||||
name: "active_orders".to_string(),
|
||||
table_type: "VIEW".to_string(),
|
||||
comment: None,
|
||||
parent_schema: None,
|
||||
parent_name: None,
|
||||
},
|
||||
test_table_info("users"),
|
||||
super::db::TableInfo {
|
||||
name: "active_users".to_string(),
|
||||
table_type: "VIEW".to_string(),
|
||||
comment: None,
|
||||
parent_schema: None,
|
||||
parent_name: None,
|
||||
},
|
||||
];
|
||||
let object_types = vec!["VIEW".to_string()];
|
||||
|
||||
let filtered = filter_table_infos(tables, None, Some(1), Some(1), Some(&object_types));
|
||||
|
||||
assert_eq!(filtered.len(), 1);
|
||||
assert_eq!(filtered[0].name, "active_users");
|
||||
}
|
||||
|
||||
#[cfg(feature = "duckdb-bundled")]
|
||||
#[test]
|
||||
fn duckdb_list_databases_includes_attached_database() {
|
||||
|
|
@ -954,7 +1044,7 @@ async fn list_objects_once(
|
|||
PoolKind::Postgres(p) => db::postgres::list_objects(p, schema).await,
|
||||
_ => {
|
||||
drop(connections);
|
||||
Ok(list_tables_core(state, connection_id, database, schema, None, None, None)
|
||||
Ok(list_tables_core(state, connection_id, database, schema, None, None, None, None)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|table| db::ObjectInfo {
|
||||
|
|
@ -1473,7 +1563,20 @@ pub async fn get_table_ddl_core(
|
|||
database: &str,
|
||||
schema: &str,
|
||||
table: &str,
|
||||
object_type: Option<db::ObjectSourceKind>,
|
||||
) -> Result<String, String> {
|
||||
if matches!(object_type, Some(db::ObjectSourceKind::View)) {
|
||||
let source =
|
||||
get_object_source_core(state, connection_id, database, schema, table, db::ObjectSourceKind::View).await?;
|
||||
let database_type = connection_config(state, connection_id).await.map(|config| config.db_type);
|
||||
return Ok(crate::object_source_sql::build_view_ddl_sql(crate::object_source_sql::BuildViewDdlInput {
|
||||
database_type,
|
||||
schema: if schema.trim().is_empty() { None } else { Some(schema.to_string()) },
|
||||
name: table.to_string(),
|
||||
source: source.source,
|
||||
}));
|
||||
}
|
||||
|
||||
let pool_key = state.get_or_create_pool(connection_id, Some(database)).await?;
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2746,6 +2746,7 @@ where
|
|||
Some(table),
|
||||
Some(1),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
|
|
@ -2761,6 +2762,7 @@ where
|
|||
Some(table),
|
||||
Some(1),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map(|tables| !tables.is_empty())
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ pub struct SchemaQuery {
|
|||
pub limit: Option<usize>,
|
||||
pub offset: Option<usize>,
|
||||
pub object_type: Option<dbx_core::db::ObjectSourceKind>,
|
||||
pub object_types: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn list_databases(
|
||||
|
|
@ -42,6 +43,9 @@ pub async fn list_tables(
|
|||
) -> Result<Json<serde_json::Value>, AppError> {
|
||||
let database = q.database.as_deref().unwrap_or("");
|
||||
let schema = q.schema.as_deref().unwrap_or("");
|
||||
let object_types = q.object_types.as_ref().map(|value| {
|
||||
value.split(',').map(str::trim).filter(|value| !value.is_empty()).map(str::to_string).collect::<Vec<_>>()
|
||||
});
|
||||
let result = dbx_core::schema::list_tables_core(
|
||||
&state.app,
|
||||
&q.connection_id,
|
||||
|
|
@ -50,6 +54,7 @@ pub async fn list_tables(
|
|||
q.filter.as_deref(),
|
||||
q.limit,
|
||||
q.offset,
|
||||
object_types.as_deref(),
|
||||
)
|
||||
.await
|
||||
.map_err(AppError)?;
|
||||
|
|
@ -153,9 +158,10 @@ pub async fn get_ddl(
|
|||
let database = q.database.as_deref().unwrap_or("");
|
||||
let schema = q.schema.as_deref().unwrap_or("");
|
||||
let table = q.table.as_deref().unwrap_or("");
|
||||
let result = dbx_core::schema::get_table_ddl_core(&state.app, &q.connection_id, database, schema, table)
|
||||
.await
|
||||
.map_err(AppError)?;
|
||||
let result =
|
||||
dbx_core::schema::get_table_ddl_core(&state.app, &q.connection_id, database, schema, table, q.object_type)
|
||||
.await
|
||||
.map_err(AppError)?;
|
||||
Ok(Json(result))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ async fn handle_list_tables_data(state: &Arc<AppState>, body: &str, stream: &mut
|
|||
respond_error(stream, "403 Forbidden", &e).await;
|
||||
return;
|
||||
}
|
||||
match dbx_core::schema::list_tables_core(state, &config.id, &database, &schema, None, None, None).await {
|
||||
match dbx_core::schema::list_tables_core(state, &config.id, &database, &schema, None, None, None, None).await {
|
||||
Ok(tables) => respond_json(stream, &tables).await,
|
||||
Err(e) => respond_error(stream, "500 Internal Server Error", &e).await,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,9 +30,19 @@ pub async fn list_tables(
|
|||
filter: Option<String>,
|
||||
limit: Option<usize>,
|
||||
offset: Option<usize>,
|
||||
object_types: Option<Vec<String>>,
|
||||
) -> Result<Vec<db::TableInfo>, String> {
|
||||
dbx_core::schema::list_tables_core(&state, &connection_id, &database, &schema, filter.as_deref(), limit, offset)
|
||||
.await
|
||||
dbx_core::schema::list_tables_core(
|
||||
&state,
|
||||
&connection_id,
|
||||
&database,
|
||||
&schema,
|
||||
filter.as_deref(),
|
||||
limit,
|
||||
offset,
|
||||
object_types.as_deref(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
|
@ -118,8 +128,9 @@ pub async fn get_table_ddl(
|
|||
database: String,
|
||||
schema: String,
|
||||
table: String,
|
||||
object_type: Option<db::ObjectSourceKind>,
|
||||
) -> Result<String, String> {
|
||||
dbx_core::schema::get_table_ddl_core(&state, &connection_id, &database, &schema, &table).await
|
||||
dbx_core::schema::get_table_ddl_core(&state, &connection_id, &database, &schema, &table, object_type).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
|
|
|||
Loading…
Reference in New Issue