fix(postgres): cast keyless JSON row predicates

This commit is contained in:
t8y2 committed 2026-08-01 13:01:34 +08:00
1 parent 6c41bb4da1
commit 93a119b424
1 file changed
+69
+69
View File
@@ -2463,6 +2463,11 @@ pub(crate) fn build_column_predicate(
format!("BINARY {ident} = {}", format_grid_sql_literal(value, database_type, column_info))
} else {
let literal = format_grid_sql_literal(value, database_type, column_info);
if use_binary_text_comparison {
if let Some(predicate) = postgres_keyless_json_predicate(database_type, &ident, &literal, column_info) {
return predicate;
}
}
format!("{ident} = {}", mysql_json_predicate_literal(literal, database_type, column_info))
}
}
@@ -2482,10 +2487,33 @@ fn build_save_column_predicate(
format!("BINARY {ident} = {}", format_grid_save_sql_literal(value, database_type, column_info))
} else {
let literal = format_grid_save_sql_literal(value, database_type, column_info);
if use_binary_text_comparison {
if let Some(predicate) = postgres_keyless_json_predicate(database_type, &ident, &literal, column_info) {
return predicate;
}
}
format!("{ident} = {}", mysql_json_predicate_literal(literal, database_type, column_info))
}
}
fn postgres_keyless_json_predicate(
database_type: Option<DatabaseType>,
ident: &str,
literal: &str,
column_info: Option<&DataGridColumnInfo>,
) -> Option<String> {
if !is_postgres_like_pattern_database(database_type) {
return None;
}
let normalized = column_info?.data_type.trim().to_ascii_lowercase();
let data_type = normalized.rsplit('.').next().unwrap_or(&normalized).trim_matches('"');
match data_type {
"json" => Some(format!("{ident}::text = {literal}::text")),
"jsonb" => Some(format!("{ident} = {literal}::jsonb")),
_ => None,
}
}
fn mysql_json_predicate_literal(
literal: String,
database_type: Option<DatabaseType>,
@@ -3038,6 +3066,47 @@ mod tests {
assert!(!statement.contains('\u{1}'));
}
#[test]
fn postgres_keyless_update_casts_json_predicates() {
let result = prepare_data_grid_save(DataGridSaveStatementOptions {
database_type: Some(DatabaseType::Postgres),
identifier_quote: None,
table_meta: DataGridTableMeta {
catalog: None,
database: None,
schema: Some("public".to_string()),
table_name: "profiles".to_string(),
primary_keys: vec![],
columns: Some(vec![
column("user_id", "uuid", false, None),
column("status", "text", false, None),
column("photo", "json", true, None),
column("extend_list", "jsonb", true, None),
]),
},
columns: vec!["user_id".to_string(), "status".to_string(), "photo".to_string(), "extend_list".to_string()],
source_columns: None,
rows: vec![vec![
json!("d7910cef-4188-4309-99ce-8e7b64d64869"),
json!("0"),
json!("[]"),
json!(r#"[{"type":"combobox","key":"gender","value":"C017MALE"}]"#),
]],
dirty_rows: vec![(0, vec![(1, json!("1"))])],
deleted_rows: vec![],
new_rows: vec![],
});
assert_eq!(result.validation_error, None);
assert_eq!(result.statements.len(), 1);
let statement = &result.statements[0];
assert!(statement.contains(r#""photo"::text = '[]'::text"#), "{statement}");
assert!(
statement.contains(r#""extend_list" = '[{"type":"combobox","key":"gender","value":"C017MALE"}]'::jsonb"#),
"{statement}"
);
}
#[test]
fn postgres_json_array_literals_preserve_json_documents_and_nulls() {
let value = json!([r#"{"object":true}"#, r#""text""#, "[1,2]", "plain text", "null", null]);