feat(grid): 列是否可排序 (#935)

This commit is contained in:
John Jin
2026-06-09 16:43:53 +08:00
committed by GitHub
parent 96e11935c2
commit 354d21d086
12 changed files with 55 additions and 0 deletions
@@ -381,6 +381,11 @@ function shortTypeName(t: string): string {
return t;
}
function headerColumnSortable(actualColIdx: number): boolean {
const resolved = props.result.column_sortables?.[actualColIdx];
return resolved !== undefined ? resolved : true;
}
function typeColorClass(t: string): string {
// Strip precision/scale suffix like (20,6)
const base = t.replace(/\(.*\)$/, "").toLowerCase();
@@ -6757,6 +6762,7 @@ const gridContextMenuItems = computed<ContextMenuItem[]>(() => {
</span>
</span>
<button
v-if="headerColumnSortable(col.actualColIdx)"
type="button"
class="flex h-4 w-4 shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground"
:class="
+5
View File
@@ -247,6 +247,11 @@ export interface QueryResult {
* fallback query paths, older backends). Consumers must tolerate gaps.
*/
column_types?: string[];
/**
* Sortable for each column. Parallel to `columns`. Optional and may
* be shorter/empty when a driver cannot supply sortable information.
*/
column_sortables?: boolean[];
rows: (string | number | boolean | null)[][];
affected_rows: number;
execution_time_ms: number;
@@ -158,6 +158,7 @@ fn limited_query_result(result: ChJsonResult, execution_time_ms: u128, max_rows:
QueryResult {
columns,
column_types,
column_sortables: vec![],
rows,
affected_rows: 0,
execution_time_ms,
@@ -270,6 +271,7 @@ pub async fn execute_query_with_max_rows(
Ok(QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -578,6 +578,7 @@ fn parse_elasticsearch_response(
Ok(crate::types::QueryResult {
columns: all_keys,
column_types: Vec::new(),
column_sortables: vec![],
rows,
affected_rows: row_count,
execution_time_ms: start.elapsed().as_millis(),
@@ -592,6 +593,7 @@ fn parse_elasticsearch_response(
Ok(crate::types::QueryResult {
columns,
column_types: Vec::new(),
column_sortables: vec![],
rows,
affected_rows: row_count,
execution_time_ms: start.elapsed().as_millis(),
@@ -604,6 +606,7 @@ fn parse_elasticsearch_response(
Ok(crate::types::QueryResult {
columns: vec!["status".to_string(), "response".to_string()],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![vec![serde_json::Value::Number(status.into()), serde_json::Value::String(pretty)]],
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -617,6 +620,7 @@ fn parse_elasticsearch_response(
Ok(crate::types::QueryResult {
columns: vec!["status".to_string(), "response".to_string()],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![vec![serde_json::Value::Number(status.into()), serde_json::Value::String(pretty)]],
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -1035,6 +1039,7 @@ fn parse_sql_response(body: &serde_json::Value, start: std::time::Instant) -> Op
Some(crate::types::QueryResult {
columns: column_names,
column_types: Vec::new(),
column_sortables: vec![],
rows: result_rows,
affected_rows: rows.len() as u64,
execution_time_ms: start.elapsed().as_millis(),
+3
View File
@@ -1448,6 +1448,7 @@ async fn execute_result_set_with_text_protocol_on_conn(
Ok(QueryResult {
columns,
column_types,
column_sortables: vec![],
rows: result_rows,
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -1492,6 +1493,7 @@ async fn execute_result_set_with_prepared_protocol_on_conn(
Ok(QueryResult {
columns,
column_types,
column_sortables: vec![],
rows: result_rows,
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -1555,6 +1557,7 @@ pub async fn execute_query_on_conn_with_max_rows(
Ok(QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows,
execution_time_ms: start.elapsed().as_millis(),
+4
View File
@@ -686,6 +686,7 @@ async fn execute_select_prepared(
Ok(QueryResult {
columns,
column_sortables: vec![],
rows: result_rows,
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -736,6 +737,7 @@ async fn execute_select_text(
Ok(QueryResult {
columns,
column_sortables: vec![],
rows: result_rows,
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -1432,6 +1434,7 @@ pub async fn execute_query_with_max_rows(
Ok(QueryResult {
columns: vec![],
column_sortables: vec![],
rows: vec![],
affected_rows: affected,
execution_time_ms: start.elapsed().as_millis(),
@@ -1518,6 +1521,7 @@ async fn execute_query_with_max_rows_inner(
Ok(QueryResult {
columns: vec![],
column_sortables: vec![],
rows: vec![],
affected_rows: affected,
execution_time_ms: start.elapsed().as_millis(),
+2
View File
@@ -291,6 +291,7 @@ pub async fn execute_query_with_max_rows(
Ok(QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows,
execution_time_ms: start.elapsed().as_millis(),
@@ -339,6 +340,7 @@ fn query_result_from_rqlite_result(
QueryResult {
columns: result.columns,
column_types: Vec::new(),
column_sortables: vec![],
rows: result.values,
affected_rows: 0,
execution_time_ms,
+2
View File
@@ -638,6 +638,7 @@ fn execute_query_blocking(pool: &SqliteHandle, sql: &str, max_rows: Option<usize
Ok(QueryResult {
columns,
column_types: Vec::new(),
column_sortables: vec![],
rows: result_rows,
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -650,6 +651,7 @@ fn execute_query_blocking(pool: &SqliteHandle, sql: &str, max_rows: Option<usize
Ok(QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: conn.changes(),
execution_time_ms: start.elapsed().as_millis(),
+5
View File
@@ -141,6 +141,7 @@ async fn collect_first_result_limited(
Ok(QueryResult {
columns,
column_types,
column_sortables: vec![],
rows,
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -483,6 +484,7 @@ fn push_sqlserver_result_set(results: &mut Vec<QueryResult>, result: Option<SqlS
results.push(QueryResult {
columns: result.columns,
column_types: result.column_types,
column_sortables: vec![],
rows: result.rows,
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -941,6 +943,7 @@ pub async fn execute_query_with_max_rows(
Ok(QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -953,6 +956,7 @@ pub async fn execute_query_with_max_rows(
Ok(QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: result.rows_affected().iter().sum::<u64>(),
execution_time_ms: start.elapsed().as_millis(),
@@ -988,6 +992,7 @@ pub async fn execute_batch_with_max_rows(
results.push(QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
+15
View File
@@ -303,6 +303,7 @@ pub fn duckdb_execute_with_max_rows(
Ok(db::QueryResult {
columns,
column_types: Vec::new(),
column_sortables: vec![],
rows: result_rows,
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -315,6 +316,7 @@ pub fn duckdb_execute_with_max_rows(
Ok(db::QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: affected as u64,
execution_time_ms: start.elapsed().as_millis(),
@@ -1028,6 +1030,7 @@ fn error_query_result(message: String) -> db::QueryResult {
db::QueryResult {
columns: vec!["Error".to_string()],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![vec![serde_json::Value::String(message)]],
affected_rows: 0,
execution_time_ms: 0,
@@ -1053,6 +1056,7 @@ async fn execute_multi_sqlserver(
all_results.push(db::QueryResult {
columns: vec!["Error".to_string()],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![vec![serde_json::Value::String(canceled_error())]],
affected_rows: 0,
execution_time_ms: 0,
@@ -1086,6 +1090,7 @@ async fn execute_multi_sqlserver(
all_results.push(db::QueryResult {
columns: vec!["Error".to_string()],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![vec![serde_json::Value::String(e)]],
affected_rows: 0,
execution_time_ms: 0,
@@ -1101,6 +1106,7 @@ async fn execute_multi_sqlserver(
all_results.push(db::QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: 0,
execution_time_ms: 0,
@@ -1165,6 +1171,7 @@ pub async fn execute_statements(
Ok(db::QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: total_affected,
execution_time_ms: start.elapsed().as_millis(),
@@ -1268,6 +1275,7 @@ async fn exec_tx_pg_inner(
Ok(total_affected) => Ok(db::QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: total_affected,
execution_time_ms: start.elapsed().as_millis(),
@@ -1316,6 +1324,7 @@ async fn exec_tx_mysql_inner(
Ok(db::QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: total_affected,
execution_time_ms: start.elapsed().as_millis(),
@@ -1348,6 +1357,7 @@ async fn exec_tx_sqlite_inner(
Ok(db::QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: total_affected,
execution_time_ms: start.elapsed().as_millis(),
@@ -1428,6 +1438,7 @@ async fn exec_tx_explicit_inner(
Ok(db::QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: total_affected,
execution_time_ms: start.elapsed().as_millis(),
@@ -1470,6 +1481,7 @@ async fn exec_tx_none_inner(
Ok(db::QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: total_affected,
execution_time_ms: start.elapsed().as_millis(),
@@ -1494,6 +1506,7 @@ mod tests {
Ok(db::QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: 0,
execution_time_ms: 0,
@@ -1514,6 +1527,7 @@ mod tests {
Ok(db::QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: 0,
execution_time_ms: 0,
@@ -1857,6 +1871,7 @@ mod tests {
let result = db::QueryResult {
columns: vec!["id".to_string(), "nested".to_string()],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![vec![
serde_json::json!(2_041_797_190_226_354_178_i64),
serde_json::json!([1, 2_041_797_190_226_354_178_i64]),
+2
View File
@@ -1713,6 +1713,7 @@ pub async fn execute_on_pool_with_max_rows(
Ok(db::QueryResult {
columns,
column_types: Vec::new(),
column_sortables: vec![],
rows: result_rows,
affected_rows: 0,
execution_time_ms: start.elapsed().as_millis(),
@@ -1725,6 +1726,7 @@ pub async fn execute_on_pool_with_max_rows(
Ok(db::QueryResult {
columns: vec![],
column_types: Vec::new(),
column_sortables: vec![],
rows: vec![],
affected_rows: affected as u64,
execution_time_ms: start.elapsed().as_millis(),
+4
View File
@@ -67,6 +67,10 @@ pub struct QueryResult {
/// query paths); consumers must tolerate a shorter/empty vector.
#[serde(default)]
pub column_types: Vec<String>,
/// Sortable for each column. Parallel to `columns`. Optional and may
/// be shorter/empty when a driver cannot supply sortable information.
#[serde(default)]
pub column_sortables: Vec<bool>,
pub rows: Vec<Vec<serde_json::Value>>,
pub affected_rows: u64,
pub execution_time_ms: u128,