fix(grid): deduplicate copied SQL IN tuples

Closes #6542
This commit is contained in:
t8y2
2026-08-18 06:32:44 +00:00
parent 1345e3f57b
commit 2eee29c0bf
2 changed files with 66 additions and 9 deletions
@@ -10,7 +10,7 @@ use crate::data_grid_sql::{
DataGridCopyUpdateStatementOptions, DataGridTableMeta,
};
use serde_json::Value;
use std::collections::HashSet;
use std::collections::{hash_map::Entry, HashMap, HashSet};
use std::io::Write;
pub(super) fn write_sql_in_list(
@@ -18,23 +18,31 @@ pub(super) fn write_sql_in_list(
output: &mut dyn Write,
) -> Result<(), DataGridExtractError> {
write_bytes(output, b"(")?;
for (row_index, row) in context.request.rows.iter().enumerate() {
if row_index > 0 {
write_bytes(output, b", ")?;
}
let mut seen_rows = HashMap::<Vec<u8>, ()>::new();
let mut has_output = false;
for row in &context.request.rows {
let mut tuple = Vec::new();
if context.selected_columns.len() > 1 {
write_bytes(output, b"(")?;
tuple.push(b'(');
}
for (column_index, source_index) in context.selected_source_indexes.iter().enumerate() {
if column_index > 0 {
write_bytes(output, b", ")?;
tuple.extend_from_slice(b", ");
}
let value = &row[*source_index];
let info = context.selected_column_info[column_index];
write_bytes(output, format_grid_sql_literal(value, context.request.database_type, info).as_bytes())?;
tuple.extend_from_slice(format_grid_sql_literal(value, context.request.database_type, info).as_bytes());
}
if context.selected_columns.len() > 1 {
write_bytes(output, b")")?;
tuple.push(b')');
}
if let Entry::Vacant(entry) = seen_rows.entry(tuple) {
if has_output {
write_bytes(output, b", ")?;
}
write_bytes(output, entry.key())?;
entry.insert(());
has_output = true;
}
}
write_bytes(output, b")")
@@ -187,6 +187,55 @@ fn extracts_multi_column_sql_in_as_row_value_tuples() {
assert_eq!(result.text, "((1, 'Ada'), (2, 'Grace, Hopper'))");
}
#[test]
fn sql_in_list_deduplicates_single_selected_values() {
let mut request = request(DataGridExtractorId::SqlInList);
request.selected_column_indexes = vec![0];
request.rows = vec![
vec![json!(1), json!("first")],
vec![json!(1), json!("unselected value differs")],
vec![json!(2), json!("last")],
];
let result = extract_data_grid_selection(request).expect("SQL IN extraction");
assert_eq!(result.text, "(1, 2)");
}
#[test]
fn sql_in_list_deduplicates_multi_column_tuples_in_first_seen_order() {
let mut request = request(DataGridExtractorId::SqlInList);
request.rows = vec![
vec![json!(2), json!("Grace")],
vec![json!(1), json!("Ada")],
vec![json!(2), json!("Grace")],
vec![json!(1), json!("Lovelace")],
vec![json!(1), json!("Ada")],
];
let result = extract_data_grid_selection(request).expect("SQL IN extraction");
assert_eq!(result.text, "((2, 'Grace'), (1, 'Ada'), (1, 'Lovelace'))");
}
#[test]
fn sql_in_list_deduplicates_only_identical_rendered_literals() {
let mut request = request(DataGridExtractorId::SqlInList);
request.selected_column_indexes = vec![0];
request.rows = vec![
vec![json!(1)],
vec![json!("1")],
vec![Value::Null],
vec![Value::Null],
vec![json!("O'Reilly")],
vec![json!("O'Reilly")],
];
let result = extract_data_grid_selection(request).expect("SQL IN extraction");
assert_eq!(result.text, "(1, '1', NULL, 'O''Reilly')");
}
#[test]
fn preserves_duplicate_json_columns_without_overwriting_values() {
let mut request = request(DataGridExtractorId::Json);