From 267577989ba1af96ccf73f3d4ef0c58721f15720 Mon Sep 17 00:00:00 2001 From: Gatefixer <313497061+lancedb-gatefixer[bot]@users.noreply.github.com> Date: Wed, 5 Aug 2026 23:26:26 +0000 Subject: [PATCH] test(rust): cover large indexed deletes --- rust/lancedb/src/table/delete.rs | 45 ++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/rust/lancedb/src/table/delete.rs b/rust/lancedb/src/table/delete.rs index 8f11ee019..d57ae9cf7 100644 --- a/rust/lancedb/src/table/delete.rs +++ b/rust/lancedb/src/table/delete.rs @@ -62,11 +62,12 @@ pub(crate) async fn execute_delete( #[cfg(test)] mod tests { use crate::connect; - use arrow_array::{Int32Array, RecordBatch, record_batch}; + use arrow_array::{Int32Array, RecordBatch, StringArray, record_batch}; use arrow_schema::{DataType, Field, Schema}; use std::sync::Arc; - use crate::query::ExecutableQuery; + use crate::index::Index; + use crate::query::{ExecutableQuery, QueryBase}; use futures::TryStreamExt; #[tokio::test] async fn test_delete_simple() { @@ -167,6 +168,46 @@ mod tests { assert_eq!(table.count_rows(None).await.unwrap(), 0); } + #[tokio::test] + async fn test_delete_large_in_list_with_btree_index() { + let conn = connect("memory://").execute().await.unwrap(); + let schema = Arc::new(Schema::new(vec![Field::new("id", DataType::Utf8, false)])); + let ids = StringArray::from_iter_values((0..10_000).map(|id| format!("id_{id}"))); + let batch = RecordBatch::try_new(schema, vec![Arc::new(ids)]).unwrap(); + let table = conn + .create_table("test_delete_large_in_list", batch) + .execute() + .await + .unwrap(); + + table + .create_index(&["id"], Index::BTree(Default::default())) + .execute() + .await + .unwrap(); + + let values = (0..10_000) + .step_by(10) + .map(|id| format!("'id_{id}'")) + .collect::>() + .join(","); + let predicate = format!("id IN ({values})"); + + // A large IN-list must stay on the scalar-index path. Lance compiles this + // predicate once and reuses it across all BTree pages. + let plan = table + .query() + .only_if(&predicate) + .explain_plan(false) + .await + .unwrap(); + assert!(plan.contains("ScalarIndexQuery"), "unexpected plan: {plan}"); + + let result = table.delete(&predicate).await.unwrap(); + assert_eq!(result.num_deleted_rows, 1_000); + assert_eq!(table.count_rows(None).await.unwrap(), 9_000); + } + #[tokio::test] async fn test_delete_false_increments_version() { let conn = connect("memory://").execute().await.unwrap();